leetCode每日十题---堆(难度:中等)

题目描述1

在这里插入图片描述

笔者解答1.1

class Solution {
    
    
    public int nthUglyNumber(int n) {
    
    
       int count=1;
       int num_result=1;
       while(count<n){
    
    
          num_result++;
          int num=num_result;
          boolean getone=false;
          do
          {
    
    
             getone=false;
            if(num%2==0){
    
    
              num/=2;
              getone=true;
            }else if(num%3==0){
    
    
              num/=3;
              getone=true;
            }else if(num%5==0){
    
    
              num/=5;
              getone=true; 
            }  
          }while(getone);
          if(num==1)
            count++;
       }
       return num_result;
    }
}

笔者分析1.2

这是我最初的想法,时间超时了,当然很容易想到另一种方法。后面的数是前面某一个数的2,3,5倍。因为之前没用过堆,这里就当堆入门了,直接学习题解的方法。
算法:预计算1690个丑数:
初始化预计算用到的数组nums,堆heap和哈希表Seen跟踪在堆中出现过的元素,避免重复。
循环计算丑数:弹出堆中最小的数字k并添加到数组nums中。若2k.3k,5k不存在哈希表中,则将其添加到栈中并更新哈希表。
返回在数组中预先计算好的丑数。

class Ugly{
    
    
 public int[] nums=new int[1690];
 Ugly(){
    
    
  HashSet<Long> seen=new HashSet();
  PriorityQueue<Long> heap=new PriorityQueue<Long>();
  seen.add(1L);
  heap.add(1L);
  long currUgly,newUgly;
  int[] primes=new int[]{
    
    2,3,5};
  for(int i=0;i<1690;i++)
  {
    
    
    currUgly=heap.poll();
    nums[i]=(int)currUgly;
    for(int j:primes){
    
    
     newUgly=currUgly*j;
     if(!seen.contains(newUgly)){
    
    
       seen.add(newUgly);
       heap.add(newUgly);
     }
    }
  }
 }
}
class Solution{
    
    
  public static Ugly u=new Ugly();
  public int nthUglyNumber(int n){
    
    
    return u.nums[n-1];
  }
}

题目描述2

在这里插入图片描述

笔者分析2.1

giao了,这些简单题都写不来,这真的是用堆就可以解决的嘛,虽然思路很清晰,但实现起来太麻烦了,看到题解才发现,原来好多功能是可以直接调用库函数的呀。。。哭了。但话说回来,题解这个解法确实巧妙,用哈希表来记录每个单词出现次数,用优先级队列来实现单调堆,同时控制堆大小,明白了,之后的这些题会用到很多的数据结构。。。

class Solution {
    
    
    public List<String> topKFrequent(String[] words, int k) {
    
    
     Map<String,Integer> map=new HashMap<>(words.length);
     //建立哈希表统计单词频率
     for(String word:words){
    
    
         map.put(word,map.getOrDefault(word,0)+1);
     }
     //小顶堆,相同频率下,字母顺序高的在前,方便入栈
     PriorityQueue<String> queue=new PriorityQueue<>((o1,o2)->{
    
    
         Integer o1Count=map.get(o1);
         Integer o2Count=map.get(o2);
         if(o1Count.equals(o2Count)){
    
    
             return o2.compareTo(o1);
         }else{
    
    
             return o1Count-o2Count;
         }
     });
     //维持topK频率的单词
     for(String word:map.keySet()){
    
    
         queue.offer(word);
         if(queue.size()>k){
    
    
             queue.poll();
         }
     }
     LinkedList<String> stack=new LinkedList<>();
     while(!queue.isEmpty()){
    
    
         stack.push(queue.poll());
     };
     return stack;
    }
}

题目描述3

在这里插入图片描述

笔者分析3.1

看完题目,感觉还行,但动不了手。。。直到看到题解,我人都傻了!下面的代码,如果不看注释,能看懂嘛(我把我能写的注释都写上去了。。)

class Solution {
    
    
    Map<Integer, Integer> dist;//存储从出发点到该点的最短路径
    public int networkDelayTime(int[][] times, int N, int K) {
    
    
        Map<Integer, List<int[]>> graph = new HashMap();/*用于存储每个顶点及其下一个顶点的信息,顶点是Integer类型,该顶点和它下一个顶点的信息包含时间长,和两端点信息,所以是一个int[]型,就是times里面的一个元素。之所以还有一个List,那是因为该顶点可以走向的下一个顶点可能有多个*/
        for (int[] edge: times) {
    
    //每一条边都是int[]类型的,现在要将times中所有的边信息,结合拼成一张图并用graph保存
            if (!graph.containsKey(edge[0]))//edge[0]是该边的起点
                graph.put(edge[0], new ArrayList<int[]>());//如果该起点没有在图中,则新建并加入
            graph.get(edge[0]).add(new int[]{
    
    edge[1], edge[2]});//以该点为起点,加入边的信息(包括终点信息和边的长度)。
        }
        dist = new HashMap();
        for (int node = 1; node <= N; ++node)
            dist.put(node, Integer.MAX_VALUE);//初始化从出发点到每个点的最短路径

        dist.put(K, 0);//出发点到自己本身的距离为0
        boolean[] seen = new boolean[N+1];//标记该顶点是否已经走过

        while (true) {
    
    
            int candNode = -1;
            int candDist = Integer.MAX_VALUE;
            for (int i = 1; i <= N; ++i) {
    
    
                if (!seen[i] && dist.get(i) < candDist) {
    
    //如果该点没有走过,而且小于原来走的距离
                    candDist = dist.get(i);//记录该距离
                    candNode = i;//记录该点
                }
            }

            if (candNode < 0) break;//如果所有点都走过,则跳出while
            seen[candNode] = true;//标记该点已经走过
            if (graph.containsKey(candNode))
                for (int[] info: graph.get(candNode))//找出所有以该点为出发点的边
                    dist.put(info[0],
                             Math.min(dist.get(info[0]), dist.get(candNode) + info[1]));//更新从出发点到该点的最短距离
        }

        int ans = 0;
        for (int cand: dist.values()) {
    
    
            if (cand == Integer.MAX_VALUE) return -1;
            ans = Math.max(ans, cand);//选出距离最长的那个输出
        }
        return ans;
    }
}

题目描述4

在这里插入图片描述

笔者分析4.1

原来二分法也可以在图形中体现并运用出来,涨知识了。这种矩阵的题,我们虽然能归纳出:每个数字都大于它左上角的所有数字,小于右下角,其它象限大小不知。但我是真没想到可以用二分法做,哎。。。尽管告诉我是二分法,我也想不到可以这样使用,佩服,佩服!

class Solution {
    
    
    public int kthSmallest(int[][] matrix, int k) {
    
    
        int n = matrix.length;
        int left = matrix[0][0];
        int right = matrix[n - 1][n - 1];
        while (left < right) {
    
    
            int mid = ((right + left)/2);
            if (check(matrix, mid, k, n)) {
    
    
                right = mid;
            } else {
    
    
                left = mid + 1;
            }
        }
        return left;
    }

    public boolean check(int[][] matrix, int mid, int k, int n) {
    
    
        int i = n - 1;
        int j = 0;
        int num = 0;
        while (i >= 0 && j < n) {
    
    
            if (matrix[i][j] <= mid) {
    
    
                num += i + 1;
                j++;
            } else {
    
    
                i--;
            }
        }
        return num >= k;
    }
}

题目描述5

在这里插入图片描述

笔者解答5.1

class Solution {
    
    
    public int[][] kClosest(int[][] points, int K) {
    
    
      Map<Integer,Integer> map=new HashMap<>();
      for(int i=0;i<points.length;i++){
    
    
          map.put(i,points[i][0]*points[i][0]+points[i][1]*points[i][1]);
      }
      PriorityQueue<Integer> queue=new PriorityQueue<>((o1,o2)->{
    
    
          return map.get(o1)-map.get(o2);
      });
      for(int i=0;i<points.length;i++)
         queue.offer(i);
      int[][] str=new int[K][2];
      int k=0;
      while(k<K){
    
    
          str[k]=points[queue.poll()];k++;
      }
      return str;
    }
}

笔者分析5.2

总算是学以致用了一回,主要还是题目简单,用其他方法一样可以很快写出来,只不过这次用的是今天学的方法,强行装了波B。

总结

感觉堆题的难度和栈的题目不是一个层次的。。。。虽然开始写的几个题都很蒙,但之后也是适应了这些手法,并成功运用这些手法解决了一个简单题??!总之,收获颇丰,打击颇大!每日打卡第六天,以下图为证。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Achenming1314/article/details/108356774