455. 分发饼干
class Solution {
/**
思路:将尽可能多的饼干分出去->每人最好吃得刚刚饱->从饥饿度最低的和最小的饼干开始匹配
*/
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);//将两个数组进行排序
Arrays.sort(s);
int i = 0;
int j = 0;
int count = 0;
while(i < g.length && j < s.length){
if(s[j] >= g[i]){//寻找最小的但能够符合最小饥饿值的饼干,若找到了,则将喂饱的人+1
count++;
i++;
}
j++;
}
return count;
}
}
135. 分发糖果
class Solution {
public int candy(int[] ratings) {
/**
1.初始化ans,使之全部为1
2.从左到右看,如果ratings[right] > ratings[left],那么ans[right] = ans[left] + 1
3.从右到左看,如果ratings[left] > ratings[right], and ans[left] <= ratings[right],then ans[left] = ans[right] + 1
注意:顺序不能乱,不能是当左->右时,变化左边那个,因为这样就迭代不起来了
*/
int[] ans = new int[ratings.length];
for(int i = 0; i < ans.length; i++){//全部都分1颗糖果
ans[i] = 1;
}
//从左往右,一个一个看
for(int i = 0; i < ratings.length - 1; i++){//如果右边的分数比左边的高,那么右边的糖果要在左边的基础上+1(因为是要求至少,所以+1就可以了)
if(ratings[i + 1] > ratings[i]){
ans[i + 1] = ans[i] + 1;
}
}
//从右往左看
for(int i = ratings.length - 1; i > 0; i--){//如果左边的分数比右边的高,但是左边得到的糖果不比右边的高,则左边得到的糖果变为右边糖果+1
if(ratings[i - 1] > ratings[i] && ans[i - 1] <= ans[i]){
ans[i - 1] = ans[i] + 1;
}
}
int sum = 0;
for(int i = 0; i < ans.length; i++){//将记录下的糖果总总数加起来
sum += ans[i];
}
return sum;
}
}
435. 无重叠区间
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
/**
找保留的最多区间数,也就是连接最紧密的所有区间
1.先将所有的区间按右界排序
2.取第一个区间的右界,看后面区间的左界是否在第一个区间内,如果在,则跳过这个区间,再判下一个区间,如果不在,那么最多区间数 + 1, 同时用于判断的右区间变为该区间的右区间,继续向下判断
*/
Arrays.sort(intervals, new Comparator() {//将所有元素,按区间右界进行从小到大排序
@Override
public int compare(int[] o1, int[] o2) {
if(o1[1] > o2[1]){
return 1;
}
if(o1[1] < o2[1]){
return -1;
}else{
return 0;
}
}
});
int count = 1;
int rightBound = intervals[0][1];//定义第一个右界
for(int i = 0; i < intervals.length; i++){拿右界一个个比元素的左界
if(intervals[i][0] >= rightBound){如果发现有元素的左界超出了前一个元素的右界,那么说明这个区间并没有重合,则把新的右界赋值
count++;
rightBound = intervals[i][1];
}
}
return intervals.length - count;
}
}
122. 买卖股票的最佳时机 II
class Solution {
public int maxProfit(int[] prices) {
/**
从头到尾遍历,如果发现prices[i + 1] - prices[i] > 0, then sum+=, i++
*/
if(prices.length == 1){
return 0;
}
int sum = 0;
for(int i = 0; i < prices.length - 1; i++){
if(prices[i + 1] - prices[i] > 0){
sum += prices[i + 1] - prices[i];
}
}
return sum;
}
}
452. 用最少数量的箭引爆气球
class Solution {
public int findMinArrowShots(int[][] points) {
/**
1.将points按照元素的右界进行排序,去一个元素的右界,判断剩下元素的左界是否在取出的右界之内,如果是,则判断下一个,如果不是,则跳到下一个元素的右界,同时count++;
*/
int count = 1;
Arrays.sort(points, new Comparator() {
@Override
public int compare(int[] o1, int[] o2) {
if(o1[1] > o2[1]){
return 1;
}
if(o1[1] < o2[1]){
return -1;
}else{
return 0;
}
}
});
int rightBound = points[0][1];
for(int i = 0;i < points.length; i++){
if(points[i][0] > rightBound){如果有气球没有重合,那么需要多一把箭,count++,然后按新气球所在的范围再判定后面的气球
rightBound = points[i][1];
count++;
}
}
return count;
}
}
376. 摆动序列
class Solution {
public int wiggleMaxLength(int[] nums) {
/*
思路:贪心算法,从左到右,把所有符合条件的,先全部记录下来再说
*/
/**
设置一个count,用来记录属于摆动序列的元素个数,从头到尾开始找。设置一个flag,用来判断下一个元素的差值需要的是正的还是负的,如果当前元素的差值为负数,那么flag=1, 正数则为-1,如果两个是相同的元素,那么flag = 0;
*/
if(nums.length == 1){
return 1;
}
if(nums.length == 2 && nums[0] == nums[1]){
return 1;
}
int count = 1;
if(nums[0] != nums[1]){
count = 2;
}
int flag = -1 * (nums[1] - nums[0]);
int res = 0;
for(int i = 2; i < nums.length; i++){
res = nums[i] - nums[i - 1];
//res < 0 and flag <= 0
//res > 0 and flag >= 0
if(res < 0 && flag <= 0){
count++;
flag = -1 * res;
}
if(res > 0 && flag >= 0){
count++;
flag = -1 * (res);
}
}
return count;
}
}
class Solution {
public int wiggleMaxLength(int[] nums) {
if(nums.length == 1){
return 1;
}
int preDiff = 0;//前一个差值,如果前一个是谷底,则是>=0,前一个是顶峰,则是<=0
int curDiff = 0;//当前一对差值
int count = 1;//因为最右边必定会有一个峰值
for(int i = 0; i < nums.length - 1; i++){
curDiff = nums[i + 1] - nums[i];
if((curDiff > 0 && preDiff <= 0) || (curDiff < 0 && preDiff >= 0)){//若pre是谷底,还没有走到顶峰,或若pre是顶峰,还没有走到谷底的时候,i就一直++,直到符合if这个条件
count++;
preDiff = curDiff;
}
}
return count;
}
}
53. 最大子序和
class Solution {
public int maxSubArray(int[] nums) {
/**
从头开始加,如果加到发现tempSum是<0的,那么就将tempSum清零,从下一个元素重新加起,将最大的那个记录在maxSum里面
*/
int maxSubArray = nums[0];
int tempSum = 0;
for(int i = 0; i < nums.length; i++){
tempSum += nums[i];
maxSubArray = Math.max(tempSum, maxSubArray);//必须在这里就开始调换,因为nums有可能全部都是负数,如果全是负数,
//则也是要在负数中找最大,而不是让后面被赋予0之后再找,因为0只是一个置零的效果,不是nums里面的元素
if(tempSum < 0){
tempSum = 0;
}
}
return maxSubArray;
}
}
55. 跳跃游戏
class Solution {
public boolean canJump(int[] nums) {
if(nums.length == 1){
return true;
}
/**
设定一个cover,第一个cover取第一个元素,此时cover的范围是[0, cover],在这个范围内找数组中的元素,看是否有i + nums[i] > cover的,
如果有,则跳到该元素这里,修改cover为i + nums[i],重复上面的判断。
每一次cover进行改变之后都要看看是否已经能覆盖到最后一个元素了,如果能,在返回true,如果经过了cover都不能,则返回false
*/
int cover = nums[0];
for(int i = 0; i <= cover; i++){//[i, cover]
cover = Math.max(i + nums[i], cover);
if(cover >= nums.length - 1){
return true;
}
}
return false;
}
}
45. 跳跃游戏 II
class Solution {
public int jump(int[] nums) {
/**
思路:到了一个元素之后,找这个元素cover的范围中,能够cover最多范围的元素,然后进行一次跳跃,得到新的范围,直到能够cover到最后的点
*/
/**
要选取最少,那么就是每次都要跳得最远
设定一个cover,cover的最开始的值就是第一个元素所能包含的范围,在这个范围内,寻找能够跳的最远的元素,然后cover改成能跳得最远元素的值
*/
if(nums.length == 1){
return 0;
}
int i = 0;
int count = 1;
int cover = i + nums[i];
while(true){
if(cover >= nums.length - 1){
return count;
}else{
int maxDistance = cover;
int targetIndex = i;
for(int j = i + 1; j <= i + nums[i]; j++){
if(j + nums[j] > maxDistance){
maxDistance = j + nums[j];
targetIndex = j;
}
}
cover = maxDistance;
i = targetIndex;
count++;
}
}
}
}
public int jump(int[] nums) {
if(nums.length == 1){
return 0;
}
int curDistance = 0;//当前cover的范围
int nextDistance = 0;//在cover范围中,某一元素能够cover的最大范围
int count = 0;
int i = 0;
while(true){
nextDistance = Math.max(nextDistance, i + nums[i]);//取cover中某一元素能够cover的最大范围
if(nextDistance >= nums.length - 1){//如果知道了该元素能够cover的范围已经到结尾了
count++;
return count;
}
if(i == curDistance){//如果已经到了当前cover的最后,那么就要进行跳跃,并且将当前的cover,换为在遍历cover范围的过程中找到的新的最大的cover的范围
curDistance = nextDistance;
count++;
}
i++;
}
}
763. 划分字母区间
class Solution {
public List partitionLabels(String s) {
/**
思路:
计算s中每一个字符出现的最后的位置,放置在edge中,然后从头开始查询字符,设定一个right值,
right值就是某一个字符出现的最后一个位置,在[i, right]的查询过程中,如果出现了更加大的right,那么
更新right,直到i == right,表明已经到了刚刚遍历过这串字串的最后一个字符
*/
List list = new LinkedList<>();
int[] edge = new int[26];
char[] chars = s.toCharArray();
for(int i = 0; i < chars.length; i++){
edge[chars[i] - 'a'] = i;//如果是同一个字符,那么chars[i] - 'a'就是相同的,那么该索引的值就能被更新
}
int right = 0;
int previous = -1;//设定-1是因为,对于第一串字符串,长度是right - 0 + 1
for(int i = 0; i < chars.length; i++){
right = Math.max(right, edge[chars[i] - 'a']);//按字母排的,而不是按索引排的
if(i == right){
list.add(i - previous);
previous = i;
}
}
return list;
}
}
56. 合并区间
class Solution {
public int[][] merge(int[][] intervals) {
/**
思路:因为合并之后的元素个数可能会发生改变,所以采用ArrayList
将区间按左边界进行排列,记录下每一次新元素的左边界start, 然后进行遍历,
如果intervals[i][左边界] < intervals[i - 1][右边界],那么对intervals[i]进行扩大,
扩大为intervals[i]和intervals[i - 1]中,有边界更大的那个,
即intervals[i][1] = Math.max(intervals[i][1], intervals[i - 1][1])
*/
List res = new ArrayList<>();
Arrays.sort(intervals, new Comparator() {//按左边界进行排序,按有边界会出错
@Override
public int compare(int[] o1, int[] o2) {
if(o1[0] > o2[0]){
return 1;
}
if(o1[0] < o2[0]){
return -1;
}else{
return 0;
}
}
});
int start = intervals[0][0];
for(int i = 1; i < intervals.length; i++){
if(intervals[i][0] > intervals[i - 1][1]){
res.add(new int[]{start, intervals[i - 1][1]});
start = intervals[i][0];
}else{
intervals[i][1] = Math.max(intervals[i - 1][1], intervals[i][1]);//若发生重合了,则进行修改,将该区间不断地扩大,
//使之产生一种递进的方式
}
}
res.add(new int[]{start, intervals[intervals.length - 1][1]});//将最后一个元素所覆盖的范围放进去
return res.toArray(new int[res.size()][]);
}
}
待后续补充