1.跳跃游戏2(力扣45)
本题需要得到跳跃到最后一个位置的最小步数,用curDistance和maxDistance存放当前可以覆盖的范围和该范围内能达到的最大范围,当走到当前可覆盖范围的最后一个时,将curDistance更新为maxDistance,并且步数加一,如果maxDistance达到或者超过最后一个位置则步数加一后返回步数。
public int jump(int[] nums) { if(nums.length == 1) return 0; //记录跳跃的次数 int count=0; //当前的覆盖最大区域 int curDistance = 0; //最大的覆盖区域 int maxDistance = 0; for (int i = 0; i < nums.length; i++) { //在可覆盖区域内更新最大的覆盖区域 maxDistance = Math.max(maxDistance,i+nums[i]); //说明当前一步,再跳一步就到达了末尾 if (maxDistance>=nums.length-1){ count++; break; } //走到当前覆盖的最大区域时,更新下一步可达的最大区域 if (i==curDistance){ curDistance = maxDistance; count++; } } return count; }
2.k次取反后最大化的数组和(力扣1005)
对于负数,尽量反转绝对值大的,收益最高;对于正数,尽量反转绝对值小的,损失最低。因此按照绝对值排序,从后往前遍历,遇到负数且k不为0时反转,直至k为0或没有负数了,若k为0则直接对数组求和,否则判断k为奇数还是偶数,若是奇数则反转第一位后求和,若是偶数则也直接求和。
public int largestSumAfterKNegations(int[] nums, int k) { List<Integer> list = new ArrayList<>(); for (int num : nums) { list.add(num); } Collections.sort(list, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(Math.abs(o1),Math.abs(o2)); } }); int ans = 0; for (int i = list.size() - 1; i >= 0; i--) { if (k > 0 && list.get(i) < 0) { ans += -list.get(i); k--; } else { ans += list.get(i); } } if (k % 2 != 0) { ans -= 2 * Math.abs(list.get(0)); } return ans; }
*3.加油站(力扣134)
本题首先暴力解法判断从每个位置开始能否转一圈,超时。采用贪心策略,利用totalSum记录总共的剩余油量,如果总剩余油量小于零,则怎样都无法转一圈;若总剩余油量大于等于零,则一定可以转一圈,利用curSum记录当前和,一旦当前和小于零则在此之前所有位置都不能作为起始位置(因为无法到达下一个位置),记录此位置的下一个位置并将当前和清零,后面再遇到则覆盖,直到便利完成,则记录的就是最后一个当前和小于零的位置的下一个位置,该位置一定能转一圈。非常好的贪心解决思路!
public int canCompleteCircuit(int[] gas, int[] cost) { // //暴力解法 // for (int i = 0; i < gas.length; i++) { // int rest = gas[i]-cost[i]; // int index = (i+1)% gas.length; // while (rest>=0 && index!=i){ // rest += gas[index] - cost[index]; // index = (index+1)% gas.length; // } // if(rest >=0 &&index==i) // return i; // } // return -1; int totalSum = 0; int curSum = 0; int index = 0; for (int i = 0; i < gas.length; i++) { totalSum += gas[i] - cost[i]; curSum += gas[i] - cost[i]; if(curSum < 0){ curSum = 0; index = (i+1)% gas.length; } } //油不够跑一圈的 if (totalSum < 0) return -1; else return index; }
4.分发糖果(力扣135)
本题需要考虑当前值的左和右,因此先从前向后遍历一次,再从后向前便利一次,保证当前值的左和右分配糖果时都符合条件。每个局部最优时达到全局最优。
public int candy(int[] ratings) { //记录最后给每个孩子分配糖果的值的数组 int[] arr = new int[ratings.length]; //每个孩子最少一个 Arrays.fill(arr,1); //从前往后如果后一个大于前一个则后一个的值在前一个的基础上加一 for (int i = 1; i < ratings.length; i++) { if(ratings[i] > ratings[i-1]) arr[i] = arr[i-1] + 1; } //从后往前如果前一个大于后一个则前一个的值在后一个的基础上加一(如果本身分配的就更多则不加一) for (int i = ratings.length-1; i >= 1; i--) { if(ratings[i-1] > ratings[i] && arr[i-1] <= arr[i]) arr[i-1] = arr[i] + 1; } int sum = 0; for (int i = 0; i < arr.length; i++) { sum += arr[i]; } return sum; }
今天的题十分的烧脑,还是菜,还得学。。另外又是想老婆的一天,唉。