牛客NC392 参加会议的最大数目【中等 贪心+小顶堆 Java/Go/PHP 力扣1353】

题目



题目链接:

https://www.nowcoder.com/practice/4d3151698e33454f98bce1284e553651

https://leetcode.cn/problems/maximum-number-of-events-that-can-be-attended/description/

思路

 贪心+优先级队列

Java代码

java 复制代码
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param meetings int整型ArrayList<ArrayList<>>
     * @return int整型
     */
    public int attendmeetings (ArrayList<ArrayList<Integer>> meetings) {
        //贪心+优先级队列
        //力扣1353. 最多可以参加的会议数目    力扣上题目描述的更好
        int ans = 0, max = -1; //max为最后一个会议的结束时间
        //按会议结束时间排序
        PriorityQueue<Integer> q = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer a, Integer b) {
                return a - b;
            }
        });

        // key -> 第 i 天, value -> 第 i 天开始的会议的结束时间
        Map<Integer, List<Integer>> map = new HashMap<>();
        for (ArrayList<Integer> e : meetings) {
            //将开始时间相同的所有会议的结束时间放一起
            if (!map.containsKey(e.get(0))) {
                map.put(e.get(0), new ArrayList<>());
            }
            map.get(e.get(0)).add(e.get(1));
            //max为最后一个会议的会议结束时间
            max = Math.max(e.get(1), max);
        }

        // 整体思路就是从1开始到最晚结束时间依次遍历一遍,然后挑选此时间要进行的会议;
        // 而队列的作用就是存储未进行的会议;挑选的判断条件就是挑选的时间不能小于此时的时间,
        // 因为队列中存储的是每个会议最晚进行时间,即,结束时间
        for (int i = 1; i <= max ; i++) {
            if (map.containsKey(i)) {
                for (Integer cur : map.get(i)) {
                    q.add(cur);
                }
            }

            while (!q.isEmpty() && q.peek() < i) {
                q.poll();
            }
            if (!q.isEmpty()) {
                ans++;
                q.poll();
            }
        }

        return ans;
    }
}

Go代码

go 复制代码
package main

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 *
 * @param meetings int整型二维数组
 * @return int整型
 */
func attendmeetings(meetings [][]int) int {
	//贪心+优先级队列

	//自己实现的升序堆,按meetings里的结束时间排序
	h := Heap{make([]int, 10), 0}
	lastday := -1 //最后会议结束时间
	//key: 会议开始是第key天,开始时间的相同的会议的结束时间放同个一list中
	daymap := map[int][]int{}
	for _, e := range meetings {
		start := e[0]
		end := e[1]

		_, ok := daymap[start]
		if !ok {
			daymap[start] = []int{}
		}

		daymap[start] = append(daymap[start], end)

		if lastday < end {
			lastday = end
		}
	}

	ans := 0

	// 整体思路就是从1开始到最晚结束时间依次遍历一遍,然后挑选此时间要进行的会议;
	// 而队列的作用就是存储未进行的会议;挑选的判断条件就是挑选的时间不能小于此时的时间,
	// 因为队列中存储的是每个会议最晚进行时间,即,结束时间
	for i := 1; i <= lastday; i++ {
		_, ok := daymap[i]

		if ok {

			list := daymap[i]
			for _, v := range list {
				h.add(v)
			}
		}

		for h.Size > 0 && h.peek() < i {
			h.remove()
		}

		if h.Size > 0 {

			ans++
			h.remove()
		}
	}

	return ans
}

type Heap struct {
	Arr  []int
	Size int
}

func (h *Heap) ensure(length int) { //堆的扩容
	old := len(h.Arr)
	if old >= length {
		return
	}

	newSize := old + old>>1
	newArr := make([]int, newSize)
	for i := 0; i < old; i++ {
		newArr[i] = h.Arr[i]
	}

	h.Arr = newArr
}

func (h *Heap) add(x int) { //往堆中添加元素
	idx := h.Size
	h.ensure(idx + 1)
	h.Arr[idx] = x
	h.shiftup(idx)
	h.Size++
}

func (h *Heap) shiftup(idx int) { //堆的上滤
	base := h.Arr[idx]

	for idx > 0 {
		pid := (idx - 1) >> 1
		parent := h.Arr[pid]

		if base >= parent {
			break
		}

		h.Arr[idx] = parent
		idx = pid
	}
	h.Arr[idx] = base
}

func (h *Heap) peek() int {
	return h.Arr[0]
}

func (h *Heap) remove() int {
	ans := h.Arr[0]
	idx := h.Size
	h.Arr[0] = h.Arr[idx-1]
	h.shiftdown(0)
	h.Size--

	return ans
}

func (h *Heap) shiftdown(idx int) { //下窜,其实可以不传idx,默认是0,从0下标下窜
	base := h.Arr[idx]
	half := h.Size >> 1

	for idx < half {
		cidx := idx<<1 + 1
		right := cidx + 1

		child := h.Arr[cidx]

		if right < h.Size && h.Arr[right] < child {
			cidx = right
			child = h.Arr[right]
		}

		if base < child {
			break
		}

		h.Arr[idx] = child
		idx = cidx
	}

	h.Arr[idx] = base
}

PHP代码

php 复制代码
<?php


/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param meetings int整型二维数组 
 * @return int整型
 */
function attendmeetings( $meetings )
{
    //贪心+优先级队列
    $ans = 0;
    $max = -1; //会议日期最大的那个日期,从每场会议的结束日期里获取
    $h = new Heap();
    //key: 会议的开始日期start,value:存结束时间的集合list,相同的start的集合
    $map = [];

    foreach ($meetings as $e){
        $start = $e[0];
        $end = $e[1];

        if(!isset($map[$start])){
            $map[$start] =[];
        }

        $map[$start][count($map[$start])] = $end;
        if($max < $end){
            $max = $end;
        }
    }

         // 整体思路就是从1开始到最晚结束时间依次遍历一遍,然后挑选此时间要进行的会议;
         // 而队列的作用就是存储未进行的会议;挑选的判断条件就是挑选的时间不能小于此时的时间,
        // 因为队列中存储的是每个会议最晚进行时间,即,结束时间
    for($i=1;$i<=$max;$i++){
        if(isset($map[$i])){
            $arr = $map[$i];
            foreach ($arr as $d){
                $h->add($d);
            }
        }

        while ($h->size >0 && $h->peek() <$i){
            $h->remove();
        }

        if ($h->size >0){
            $ans++;
            $h->remove();
        }
    }


    return $ans;
}


class Heap{ //自己的实现的升序堆
    public $arr;
    public $size;

    public function __construct()
    {
        //初始化堆
        for($i=0;$i<10;$i++){
            $this->arr[$i] =0;
        }
        $this->size =0;
    }

    public function ensure($cap){ //扩容代码
        $old = count($this->arr);
        if($old >=$cap) return;

        $newsize = $old+$old >>1;

        $newarr = [];
        for($i=0;$i<$newsize;$i++){
            $newarr[$i] =0;
            if($i<$old){
                $newarr[$i] = $this->arr[$i];
            }
        }
        $this->arr  =$newarr;
    }


    public function add($x){
        $idx = $this->size;
        $this->ensure($idx+1);
        $this->arr[$idx] =$x;
        $this->shiftup($idx);
        $this->size++;

    }

    public function shiftup($idx){ //上滤
        $base = $this->arr[$idx];
        while ($idx >0){
            $pid = ($idx-1) >> 1; //父id
            $parent = $this->arr[$pid];

            if($base >$parent) break;

            $this->arr[$idx] = $parent;
            $idx = $pid;


        }

        $this->arr[$idx] = $base;
    }

    public function peek(){
        return $this->arr[0];
    }

    public function remove(){
        $ans =$this->arr[0];
        $curlen = $this->size;
        $this->arr[0] = $this->arr[$curlen-1];

        $this->size--;
        $this->shiftdown(0);


        return $ans;
    }

    //下窜,可以不用传idx参数,一般是从0开始下窜,idx=0
    public function shiftdown($idx){
        $base = $this->arr[$idx];
        $half = $this->size >> 1;

        while ($idx<$half) {
            $cidx = ($idx<<1) +1;

            $right = $cidx+1;
            $child = $this->arr[$cidx];

            if($right < $this->size && $child > $this->arr[$right]){
                $cidx = $right;
                $child = $this->arr[$right];
            }

            if($child > $base) break;
            $this->arr[$idx] =$child;
            $idx= $cidx;


        }
        $this->arr[$idx] = $base;
    }
}
相关推荐
.Cnn5 分钟前
用邻接矩阵实现图的深度优先遍历
c语言·数据结构·算法·深度优先·图论
2401_8582861111 分钟前
101.【C语言】数据结构之二叉树的堆实现(顺序结构) 下
c语言·开发语言·数据结构·算法·
Beau_Will17 分钟前
数据结构-树状数组专题(1)
数据结构·c++·算法
迷迭所归处20 分钟前
动态规划 —— 子数组系列-单词拆分
算法·动态规划
爱吃烤鸡翅的酸菜鱼21 分钟前
Java算法OJ(8)随机选择算法
java·数据结构·算法·排序算法
寻找码源1 小时前
【头歌实训:利用kmp算法求子串在主串中不重叠出现的次数】
c语言·数据结构·算法·字符串·kmp
Matlab精灵1 小时前
Matlab科研绘图:自定义内置多款配色函数
算法·matlab
诚丞成1 小时前
滑动窗口篇——如行云流水般的高效解法与智能之道(1)
算法
带多刺的玫瑰3 小时前
Leecode刷题C语言之统计不是特殊数字的数字数量
java·c语言·算法
爱敲代码的憨仔3 小时前
《线性代数的本质》
线性代数·算法·决策树