目录
455.分发饼干
leetcode题目链接:https://leetcode.cn/problems/assign-cookies/
leetcode AC记录:
思路:饼干和胃口数组分别进行排序,遍历饼干和胃口,如果饼干i大于等于胃口,结果自增, 如果饼干i小于胃口,结果不变,i++,j不变。
代码如下:
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int res = 0;
int sIndex = 0;
int gIndex = 0;
while(gIndex < g.length && sIndex < s.length) {
if(g[gIndex] <= s[sIndex]) {
res++;
gIndex++;
}
sIndex++;
}
return res;
}
376. 摆动序列
leetcode题目链接:https://leetcode.cn/problems/wiggle-subsequence/description/
leetcode AC记录:
思路:本体可以理解为升降的次数,如果方向改变了结果自增。
代码如下:
//本体可以理解为升降的次数
public int wiggleMaxLength(int[] nums) {
int res = 1;
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
int upOrDown = 2; // 0 降 1 升
for(int i = 1;i <= nums.length -1;i++) {
//下降
if(nums[i-1] > nums[i]) {
//初始值或者之前是上升,子序列长度增加
if(upOrDown == 2 || upOrDown == 1) {
res++;
upOrDown = 0;
}
//上升
} else if(nums[i-1] < nums[i]) {
if(upOrDown == 2 || upOrDown == 0) {
res++;
upOrDown = 1;
}
}
}
return res;
}
53. 最大子序和
leetcode题目链接:https://leetcode.cn/problems/maximum-subarray/
leetcode AC记录:
思路:当数组遍历到i时,以i结尾的最大的数组和为,Math.max(之前的最大和sum+nums[i], nums[i]),用变量记录遍历过程中的最大数组和即可。
代码如下:
public int maxSubArray(int[] nums) {
int currentSum = nums[0];
int res = currentSum;
for(int i = 1;i < nums.length;i++) {
currentSum = nums[i] > currentSum + nums[i] ? nums[i] : currentSum + nums[i];
res = res > currentSum ? res : currentSum;
}
return res;
}
122.买卖股票的最佳时机II
leetcode题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/
leetcode AC记录:
思路:如果股票明天上升就卖。
代码如下:
public int maxProfit(int[] prices) {
int res = 0;
for(int i = 1;i <= prices.length - 1;i++) {
if(prices[i-1] < prices[i]) {
res += prices[i] - prices[i-1];
}
}
return res;
}
55. 跳跃游戏
leetcode题目链接:https://leetcode.cn/problems/jump-game/
leetcode AC记录:
思路:当前位置 i 能跳的位移受限于nums[i],也就是只能跳到 i 到 i+nums[i]的下标位置,跳到哪个位置是最合适的呢?就需要看以 下标 [i, i + nums[i]] 为起跳点的最远跳跃位置,即Max(nums[i] + i, nums[ i + nums[i]] + i + nums[i]),取最大值对应的下标作为i跳到的位置。
代码如下:
public boolean canJump(int[] nums) {
int index = 0;
int length = nums.length;
while(index < nums.length) {
if(index >= nums.length -1) {
return true;
} else if(nums[index] == 0) {
return false;
}
int maxIndex = Integer.MIN_VALUE;
for(int i = 1; i <= nums[index]; i++) {
if(nums[index + i] + i + index >= nums.length -1) {
return true;
}
if(maxIndex < 0 || nums[index + i] + i + index > maxIndex + nums[maxIndex]) {
maxIndex = index + i;
}
}
index = maxIndex;
}
return true;
}
45.跳跃游戏II
leetcode 题目链接:https://leetcode.cn/problems/jump-game-ii/
leetcode AC记录:
思路:同上题。
代码如下:
public int jump(int[] nums) {
int index = 0;
int length = nums.length;
int res = 0;
while(index < nums.length -1) {
int num = nums[index];
int maxIndex = index;
for(int i = 1;i <= num;i++) {
if(index + i >= nums.length - 1) {
return res + 1;
} else if(nums[index + i] + index + i > nums[maxIndex] + maxIndex) {
maxIndex = index + i;
}
}
index = maxIndex;
res++;
// if(nums[maxIndex] + maxIndex >= nums.length -1) {
// return res+1;
// }
}
return res;
}
1005.K次取反后最大化的数组和
leetcode 题目链接:https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations/
leetcode AC记录:
思路:使用优先队列,每次取最小的进行替换。
代码如下:
public int largestSumAfterKNegations(int[] nums, int k) {
//每次选择最小的进行替换
PriorityQueue<Integer> queue = new PriorityQueue<>();
for(int i = 0;i < nums.length;i++) {
queue.offer(nums[i]);
}
for(int i = 0;i < k;i++) {
Integer value = queue.poll();
queue.offer(-value);
}
int res = 0;
while(!queue.isEmpty()) {
res += queue.poll();
}
return res;
}
134. 加油站
leetcode题目链接:https://leetcode.cn/problems/gas-station/
leetcode AC记录:
思路:遍历数组,累加油差,记录最小油差值,如果油差小于0,则不能完成,如果大于0,则最小油差值的下一个就是目标值。
代码如下:
public int canCompleteCircuit(int[] gas, int[] cost) {
int minSum = Integer.MAX_VALUE;
int sum = 0;
int res = 0;
for(int i = 0;i < gas.length;i++) {
sum += gas[i] - cost[i];
if(sum < minSum) {
minSum = sum;
res = i;
}
}
return sum < 0 ? -1 : (res + 1) % gas.length;
}
135. 分发糖果
leetcode题目链接:https://leetcode.cn/problems/candy/
leetcode AC记录:
思路:两个方向处理。先从左向右遍历数组,处理左关系,然后从右向左遍历,处理右关系。
左右关系指当前位置比左或者右评分高时,当前糖果值应该做加1操作。
代码如下:
public int candy(int[] ratings) {
if(ratings == null || ratings.length <= 0) {
return 0;
}
int res = 0;
int[] nums = new int[ratings.length];
Arrays.fill(nums, 1);
for(int i = 0; i < ratings.length;i++) {
if(i > 0 && ratings[i] > ratings[i-1]) {
nums[i] = nums[i-1] + 1;
}
}
for(int i = ratings.length-1; i >= 0;i--) {
if(i < ratings.length-1 && ratings[i] > ratings[i+1]) {
nums[i] = Math.max(nums[i+1] + 1, nums[i]);
}
res += nums[i];
}
return res;
}
860.柠檬水找零
leetcode题目链接:https://leetcode.cn/problems/lemonade-change/
leetcode AC记录:
思路:使用变量tencount记录10的个数,使用fivecount记录5的个数,第一个如果是非5的钱,直接返回false。先收钱,再找零,如果收到5美分,fivecount++,如果收到10美分,tencount++,如果收到20美分,优先使用10美分找零,如果没有10美分,使用5美分找零。
代码如下:
public boolean lemonadeChange(int[] bills) {
int tenCount = 0;
int fiveCount = 0;
if(bills[0] != 5) {
return false;
}
for(int i = 0;i < bills.length;i++) {
//第一步,收钱
if(bills[i] == 5) {
fiveCount++;
} else if(bills[i] == 10) {
tenCount++;
}
//第二步,找钱
if(bills[i] == 10) {
fiveCount--;
} else if(bills[i] == 20) {
if(fiveCount > 0 && tenCount > 0) {
fiveCount--;
tenCount--;
} else {
fiveCount -= 3;
}
}
if(fiveCount < 0 || tenCount < 0) {
return false;
}
}
return true;
}
406.根据身高重建队列
leetcode题目链接:https://leetcode.cn/problems/queue-reconstruction-by-height/
leetcode AC记录:
思路:
1. 给people排序,按照个子h倒序,然后按照k顺序
2. 个子高的在前面,个子低的在后,
3. 得到[7,0],[7,1],[6,1],[5,0],[5,2],[4,4]]
4. 依题意,比people[i][0]高的有people[i][1]个
5. 只要从前往后遍历,将people[i] 放置到下标people[i][1]处即可
6.这是因为遍历途中,始终有people[i][0]小于等于之前的值people[j][0]
代码如下:
public int[][] reconstructQueue(int[][] people) {
Arrays.sort(people, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] == o2[0] ? o1[1] - o2[1] : o2[0] - o1[0];
}});
//给people排序,按照个子h倒序,然后按照k顺序
//个子高的在前面,个子低的在后,
//得到[7,0],[7,1],[6,1],[5,0],[5,2],[4,4]]
//依题意,比people[i][0]高的有people[i][1]个
//只要从前往后遍历,将people[i] 放置到下标people[i][1]处即可
//这是因为遍历途中,始终有people[i][0]小于等于之前的值people[j][0]
int index = 0;
while(index < people.length) {
int[] hj = people[index];
if(hj[1] != index) {
int targetIndex = hj[1];
int chapaiIndex = index - 1;
while(chapaiIndex >= targetIndex) {
people[chapaiIndex+1] = people[chapaiIndex];
chapaiIndex--;
}
people[targetIndex] = hj;
}
index++;
}
return people;
}
452. 用最少数量的箭引爆气球
leetcode题目链接:https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/
leetcode AC记录:
思路:我们的要求是全部引爆,先按照左区间进行排序,再按照右区间进行排序(注意不能直接相减,会超出int范围)。如果数组为空,返回0。初始化结果数量为1,使用left和right记录左右区间值,如果当前区间和【left,right】重叠,使用left和right记录重叠区间左右范围,结果数量不变;如果不重叠,left和right指向当前区间大小,结果数量自增。
代码如下:
public int findMinArrowShots(int[][] points) {
Arrays.sort(points, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if(o1[0] == o2[0]) {
if(o1[1] > o2[1]) {
return 1;
} else if(o1[1] == o2[1]) {
return 0;
} else {
return -1;
}
} else {
if(o1[0] > o2[0]) {
return 1;
} else if(o1[0] == o2[0]) {
return 0;
} else {
return -1;
}
}
}
});
System.out.println(Arrays.deepToString(points));
int res = 1;
int left = points[0][0];
int right = points[0][1];
for(int i = 1;i < points.length;i++) {
if(left <= points[i][0] && right >= points[i][0]) {
left = Math.max(left, points[i][0]);
right = Math.min(right, points[i][1]);
} else {
left = points[i][0];
right = points[i][1];
res++;
}
}
return res;
}
435. 无重叠区间
leetcode题目链接:https://leetcode.cn/problems/non-overlapping-intervals/
leetcode AC记录:
思路:对区间进行排序(先按照左区间排序,左区间相等再按照右区间排序)。初始化left,right为元素0的左右限,从下标1开始遍历区间数组,如果当前区间和【left,right】重合,结果数量加1,right和left取最小的左右限。如果不重合,left和right取当前区间值。
代码如下:
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] == o2[0] ? o1[1] - o2[1] : o1[0] - o2[0];
}
});
int res = 0;
int left = intervals[0][0];
int right = intervals[0][1];
for(int i = 1;i < intervals.length;i++) {
//区间重合
if(left <= intervals[i][0] && right > intervals[i][0]) {
left = Math.max(intervals[i][0], left);
right = Math.min(intervals[i][1], right);
res++;
} else {
left = intervals[i][0];
right = intervals[i][1];
}
}
return res;
}
763.划分字母区间
leetcode题目链接:https://leetcode.cn/problems/partition-labels/
leetcode AC记录:
思路:开辟数组zimulastIndexArr,大小26用来记录字母最后一次出现的下标。遍历s,取字母数组s第i个值,然后到zimulastIndexArr中找该字母出现的最后一次下标位置lastindex,如果lastindex<=i,则需要切分。否则遍历i到lastindex,按照上述操作更新最大的lastindex。
代码如下:
public List<Integer> partitionLabels(String s) {
int[] zimulastIndexArr = new int[26];
Arrays.fill(zimulastIndexArr, -1);
for(int i = 0;i < s.length();i++) {
zimulastIndexArr[s.charAt(i)-'a'] = i;
}
List<Integer> res = new ArrayList<>(16);
int index = 0;
while(index < s.length()) {
char c = s.charAt(index);
int cLastIndex = zimulastIndexArr[c-'a'];
int i = index + 1;
while(i <= cLastIndex) {
c = s.charAt(i);
cLastIndex = Math.max(zimulastIndexArr[c-'a'], cLastIndex);
i++;
}
res.add(i - index);
index = i;
}
return res;
}
56. 合并区间
leetcode题目链接:https://leetcode.cn/problems/merge-intervals/
leetcode AC记录:
思路:使用List<int[]>结构保存结果,初始化时添加intervals[0]到结果数组中,并定义left为元素0的左区间,定义right为元素0的右区间,intervals排序(按左区间,左区间相同按照右区间)。然后从1开始遍历intervals,如果【left,right】和当前元素的区间重叠,更新结果集最后一个元素的left和right :left取两个左区间的最小值,right取两个右区间的最大值。
代码如下:
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] == o2[0] ? o1[1] - o2[1] : o1[0] - o2[0];
}});
List<int[]> res = new ArrayList<>();
int left = intervals[0][0];
int right = intervals[0][1];
res.add(new int[]{left, right});
for(int i = 1;i < intervals.length;i++) {
if(left <= intervals[i][0] && right >= intervals[i][0]) {
right = Math.max(right, intervals[i][1]);
int[] arr = res.get(res.size()-1);
arr[1] = right;
} else {
res.add(new int[]{intervals[i][0], intervals[i][1]});
left = intervals[i][0];
right = intervals[i][1];
}
}
return res.toArray(new int[res.size()][]);
}
738.单调递增的数字
leetcode题目链接:https://leetcode.cn/problems/monotone-increasing-digits/
leetcode AC记录:
思路:将数字转为字符串,从前往后遍历 i是否有nums[i] <= nums[i+1],如果不符合,则进行如下操作:i位置的数字减1,i+1到nums.length-1的数字变为都变为9,然后从i=0开始重新遍历。
代码如下:
public int monotoneIncreasingDigits(int n) {
String str = String.valueOf(n);
char[] nums = str.toCharArray();
for(int i = 0;i < nums.length-1;i++) {
char c = nums[i];
char c1 = nums[i+1];
if(c > c1) {
nums[i] -= 1;
int j = i+1;
while(j < nums.length) {
nums[j++] = '9';
}
i = -1;
}
}
int res = 0;
int value = 1;
for(int i = nums.length-1;i >= 0;i--) {
res += (nums[i] - '0') * value;
value *= 10;
}
return res;
}
968.监控二叉树
leetcode题目链接:https://leetcode.cn/problems/binary-tree-cameras/
leetcode AC记录:
思路:
1.使用0表示当前节点有摄像头,使用1表示当前节点有覆盖,使用2表示当前节点无覆盖
2.左孩子有摄像头 右孩子有摄像头 当前节点有覆盖 res不变
3.左孩子有覆盖 右孩子有摄像头 当前节点有覆盖 res不变
4.左孩子无覆盖 右孩子有摄像头 当前节点需要覆盖左孩子 res增加1
5.左孩子无覆盖 右孩子无覆盖 当前节点需要覆盖左右孩子 res增加1
5.左孩子有覆盖 右孩子有覆盖 当前节点无覆盖 res不变
6. 如果节点为空,说明是有覆盖
代码如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int minCameraCover(TreeNode root) {
int[] res = new int[1];
if(reverse(root, res) == 2) {
res[0]++;
}
return res[0];
}
//使用0表示当前节点有摄像头,使用1表示当前节点有覆盖,使用2表示当前节点无覆盖
//左孩子有摄像头 右孩子有摄像头 当前节点有覆盖 res不变
//左孩子有覆盖 右孩子有摄像头 当前节点有覆盖 res不变
//左孩子无覆盖 右孩子有摄像头 当前节点需要覆盖左孩子 res增加1
//左孩子无覆盖 右孩子无覆盖 当前节点需要覆盖左右孩子 res增加1
//左孩子有覆盖 右孩子有覆盖 当前节点无覆盖 res不变
//如果节点为空,说明是有覆盖
public int reverse(TreeNode root, int[] res) {
if(root == null) {
return 1;
}
int coverLeft = reverse(root.left, res);
int coverRight = reverse(root.right, res);
if(coverLeft == 1 && coverRight == 1) {
return 2;
} else if(coverLeft == 2 || coverRight == 2) {
res[0]++;
return 0;
} else if(coverLeft == 0 || coverRight == 0) {
return 1;
}
return 1;
}
}