刚开始看到这题,发现和上次也的丑数那题几乎一样,所以很顺利的写了出来,但是有些问题,当k比较大的时候,输出结果过大会越界,不对,不是输出结果,是在存储的时候会偶数值越界。有想过用Long才存储,但返回是Int类型,也没啥效果,归根结底还是方法不对。评论区的解法真的是神仙打架啊,太秀了,看看下面这个。
class Solution { public int getKthMagicNumber(int k) { int i3=0,i5=0,i7=0; int dp[]=new int[k]; dp[0]=1; for(int i=1;i<k;i++){ dp[i]=Math.min(Math.min(3*dp[i3],5*dp[i5]),7*dp[i7]); if(dp[i]==3*dp[i3]) i3++; if(dp[i]==5*dp[i5]) i5++; if(dp[i]==7*dp[i7]) i7++; } return dp[k-1]; } }这题思路其实不难,我开始也是说铁着心要把它写出来,结果改了两小时BUG,还有些用例通过不了。。。菜了菜了!求助评论区。优先队列还能这样用也是爱了。
class Solution { public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) { PriorityQueue<int[]> queue = new PriorityQueue<>((o1, o2) -> compare(o2, o1)); for (int i : nums1) { for (int j : nums2) { int[] arr = new int[]{i, j}; if (queue.size() < k) { queue.offer(arr); } else if (!queue.isEmpty() && compare(queue.peek(), arr) > 0) { queue.poll(); queue.offer(arr); } } } List<List<Integer>> res = new ArrayList<>(); while (!queue.isEmpty()) { int[] poll = queue.poll(); res.add(Arrays.asList(poll[0], poll[1])); } return res; } private int compare(int[] arr1, int[] arr2) { return (arr1[0] + arr1[1]) - (arr2[0] + arr2[1]); } }我真以为我写出来了的,用哈希表和递归,以为会很漂亮的通过,结果竟然是时间超时。。。再次求助于评论区:挺简单的贪心题,按照数量从大到小放就好了,大的放在前面,如果出现相同的值则先放下一个。
public int[] rearrangeBarcodes(int[] barcodes) { int[] res = new int[barcodes.length]; Map<Integer, Integer> map = new HashMap<>(); for (int barcode : barcodes) map.put(barcode, map.getOrDefault(barcode, 0) + 1); int index = 0; Queue<int[]> pq = new PriorityQueue<>((o1, o2) -> o2[0] - o1[0]); for (Integer integer : map.keySet()) pq.add(new int[]{map.get(integer), integer}); int[] p = pq.poll(); res[index++] = p[1]; p[0] -= 1; pq.add(p); while (index < res.length) { int[] cp = pq.poll(); if (cp[1]!=res[index-1]){ res[index++]=cp[1]; cp[0]-=1; }else { int[] poll = pq.poll(); res[index++]=poll[1]; poll[0]-=1; pq.add(poll); } pq.add(cp); } return res; }反思了一下下,这些看似没有头绪很复杂的题目,实现的代码其实没有想象的那么可怕,相反它可能很简洁,但这取决于你思考问题的角度,以及该问题的核心突破口。比较简单的难题并不是使用的数据结构又有多复杂,而是这个突破口不太好把握和运用。
虽然我再上一题分析中写道哪些看似难的题,其实真正的代码并不复杂。但我看到这题,又是一头雾水,心想这得多复杂啊,直到我看到评论区大佬的解法,我佛了。
class Solution { public int findCheapestPrice(int n, int[][] flights, int src, int dst, int K) { int[][] dp = new int[n][K+2]; for(int i = 0; i < n; ++i) Arrays.fill(dp[i], Integer.MAX_VALUE); for(int k = 0; k <= K+1; ++k) dp[src][k] = 0; for(int k = 1; k <= K+1; ++k) { for(int[] flight : flights) { if(dp[flight[0]][k-1] != Integer.MAX_VALUE) dp[flight[1]][k] = Math.min(dp[flight[1]][k], dp[flight[0]][k-1] + flight[2]); } } return dp[dst][K+1] == Integer.MAX_VALUE ? -1 : dp[dst][K+1]; } }个人认为,虽然这题的定位困难,但感觉比前几题要好理解多了。思路很简单,就是很容易超时,就比如我上面写的代码,超时了。观摩了下评论区大佬的想法,大小顶堆结合求中位数的方法实在太惊艳了。 大顶堆+小顶堆:可以看作大顶堆是普通版,小顶堆是实验班。数量上时刻保持小顶-大顶<=1(两堆相等或者小顶比大顶多一个)。新学生先入普通班(大顶堆),此时可能会失去平衡了,于是取大顶堆的第一个(班里最好的学生)加入实验班(小顶堆),判断若数量过多(不是等于或多一个),取第一个(实验班里最差的学生)到普通班(大顶堆)里。取中位数的时候,若两堆数量相等,则各取堆顶取平均,若小顶比大顶多一,则多的那一个就是中位数。
原来写过一个二维的,不是很难,现在三维的,感觉难度不是一个层次的,主要是这个墙太难找了,看了题解,将围墙由外向内缩减,牛!
public int trapRainWater(int[][] heights){ if(heights==null||heights.length==0)return 0; int n=heights.length; int m=heights[0].length; //用一个vis数组来标记这个位置有没有被访问过 boolean[][] vis=new boolean[n][m]; //优先队列中存放三元组[x,y,h]坐标和高度 PriorityQueue<int[]> pq=new PriorityQueue<>((o1,o2)->o1[2]-o2[2]); //先把最外一圈放进去 for(int i=0;i<n;i++){ for(int j=0;j<m;j++) { if(i==0||i==n-1||j==0||j==m-1){ pq.offer(new int[]{i,j,heights[i][j]); vis[i][j]=true; } } } int res=0; //方向数组,把dx和dy压缩成一维来做 int[] dirs={-1,0,1,0,-1};//很强 while(!pq.isEmpty()){ int[] poll=pq.poll(); //看一下周围四个方向,没访问过的话能不能往里灌水 for(int k=0;k<4;k++) { int nx=poll[0]+dirs[k]; int ny=poll[1]+dirs[k+1]; //如果位置合法且没访问过 if(nx>=0&&nx<n&&ny>=0&&ny<m&&!vis[nx][ny]){ //如果外围这一圈中最小的比当前这个还高,那就说明能往里面灌水啊 if(poll[2]>heights[nx][ny]){ res+=poll[2]-heights[nx][ny]; } //如果灌水高度得是你灌水后的高度了,如果没灌水也要取高的 pq.offer(new int[]{nx,ny,Math.max(heights[nx][ny],poll[2])}); vis[nx][ny]=true; } } } return res; } }自我感觉还是挺好的,思路清晰,代码简洁,但就是内存超出限制。。。。下面这个方法和我写的类似,通过的原因在于它用单个点的存储取代了我的长数组。
public List<List<Integer>> getSkyline(int[][] buildings) { List<List<Integer>> resList = new ArrayList<>(); if (buildings == null || buildings.length == 0 || buildings[0] == null || buildings[0].length == 0) { return resList; } //定义比较器,先按pos从小到大排序,pos相等,按height从小到大排 PriorityQueue<Point> queue = new PriorityQueue<>((o1, o2) -> { if (o1.pos != o2.pos) { return o1.pos - o2.pos; } if (o1.height != o2.height) { return o1.height - o2.height; } return 0; }); //生成queue,<第一个位置,负高度>,<第二个位置,正高度> for (int i = 0; i < buildings.length; i++) { queue.offer(new Point(buildings[i][0], -buildings[i][2])); queue.offer(new Point(buildings[i][1], buildings[i][2])); } PriorityQueue<Integer> maxHeightQueue = new PriorityQueue<>(Comparator.reverseOrder()); maxHeightQueue.offer(0); int prePeak = maxHeightQueue.peek(); while (!queue.isEmpty()) { //当当前高度是负数,说明是上升的,加到maxHeightQueue,反之移除掉 Point point = queue.poll(); if (point.height < 0) { maxHeightQueue.offer(-point.height); } else { maxHeightQueue.remove(point.height); } int curPeak = maxHeightQueue.peek(); if (curPeak != prePeak) { resList.add(Arrays.asList(point.pos, curPeak)); prePeak = curPeak; } } return resList; } class Point { int pos, height; public Point(int pos, int height) { this.pos = pos; this.height = height; } }原来N皇后问题是自己吓自己呀,就一个回溯算法,大小顶堆也是秀了我一脸,优先队列也可以花里胡哨的用。每日打卡第七天,以下图为证。