算法题不卡壳

本文探讨了贪心算法在解决系统设计题中的应用,包括多条件排序、买卖股票最佳时机、分发糖果、跳跃游戏和加油站问题等经典案例。通过排序和局部最优解来实现全局最优。同时,介绍了二叉树遍历、多条件排序、地图重建队列等复杂问题的解决策略,强调了在面对多个条件和维度时,确定优先级和逻辑的重要性。
摘要由CSDN通过智能技术生成

系统设计题

主要是考察数据结构的设计,多条件排序算法
练习题目:
1772
379
1369
1817
635
1500
355
1845

贪心算法

455.饼干分发

贪心算法基本入门题目,了解局部最优情况下,累计后达成全局最优
题目描述:需求数组g和饼干数组s,求解最大的满足数量(最多的s[i] >= g[j])
解体思路:排序需求数组和饼干数组,按需进行匹配,实现每次的最优解
在这里插入图片描述

public int findContentChildren(int[] g, int[] s) {
    // 两个数组先进行排序
    Arrays.sort(g);
    Arrays.sort(s);
    int out = 0;
    int j = 0;
    for (int i = 0; i < s.length && j < g.length; i++) {
        // 每次满足 s[i] >= g[j] 时,结果集+1,需求和饼干都往后+1
        // 不满足时,饼干+1,需求不变
        if (s[i] >= g[j]) {
            out++;
            j++;
        }
    }
    return out;
}

买卖股票的最佳时机 II

贪心算法中需要理解的题目,初步看很难一下子想通,但是有了方法和套路之后,往贪心算法考,想每次的最优,最大的利益可以转化成每次的利益相加,(最后就转化为了,只要明天价格比今天高,就进行买卖)
这种题目比较容易一下子看蒙,所以要多练习,还有就是要思路清晰

public int maxProfit(int[] prices) {
    int result = 0;        
    for (int i = 0; i < prices.length - 1; i++) {
        if (prices[i] < prices[i + 1]) {
            result+= prices[i+1] - prices[i];
        }
    }
    return result;
}

135.分发糖果

贪心算法中有难度的题目,之前考试中也遇到过,基本都是不会做,第一次做也是看着答案做,边界控制异常复杂,要十分小心,不然修修补补会浪费很多时间
类似题目有套路,利用条件要求,形成逻辑,但还是要一定的思考和经验,熟能生巧,边界的处理,只能多加练习

核心:两次变量,形成两次规则下的条件,基本生产的数据,形成最终答案

public int candy(int[] ratings) {
    int len = ratings.length;
    int[] arr = new int[len];
    // 按照左侧规则,最左先设置为1,左 < 右,即 右侧+1
    for (int i = 0; i < len; i++) {
        if (i > 0 && ratings[i - 1] < ratings[i]) {
            arr[i] = arr[i - 1] + 1;
        } else {
            arr[i] = 1;
        }
    }
    int tmp = 0;
    int result = 0;
    // 右规则,最右侧先为1, 右 < 左, 左侧+1
    for (int i = len - 1; i >= 0; i--) {
        if (i < len - 1 && ratings[i] > ratings[i + 1]) {
            tmp++;
        } else {
            tmp = 1;
        }
        // 同时满足 左右规则时,数值的的保留进行累加
        result += Math.max(tmp, arr[i]);
    }
    return result;
}

55. 跳跃游戏

之前写过的题目,再次打开,居然一下子没有想出来,看来之前写的才发现,思路和写法真的s是秒
核心点:不用拘泥于每次究竟跳跃多少步,而是看覆盖范围
两年前的写法:很巧妙,不知道是不是当时自己想出来的

public boolean canJump(int[] nums) {
     int n=1;
     for(int i=nums.length-2; i>=0;i--){
         if(nums[i]>=n){
             n=1;
         }else {
             n++;
         }
     }
     if(n>1){
         return false;
     }else {
         return true;
     }
 }

参考答案,第二次解题,过程不是很流畅

public boolean canJump(int[] nums) {
    int rang = 0;
    for (int i = 0; i < nums.length; i++) {
        // 坐标如果直接大于范围rang,结果肯定就失败了
        if (i <= rang) {
            rang = Math.max(i + nums[i], rang);
            if (rang >= nums.length-1) {
                return true;
            }
        } else {
            return false;
        }
    }
    return false;
}

134. 加油站

这道题目比较常规,常规暴力也可以解答,算是简单题目,巧妙就是要寻找出好方法
常规暴力法:

public int canCompleteCircuit(int[] gas, int[] cost) {
    // 贪心暴力遍历
    int len = gas.length;
    if (len == 1 && gas[0] == cost[0]) {
        return 0;
    }
    for (int i = 0; i < len; i++) {
        if (gas[i] <= cost[i]) {
            continue;
        }
        int res = 0;
        int index = 0;
        while (res >= 0 && index < len) {
            int tmp = (index + i) % len;
            res += gas[tmp] - cost[tmp];
            index++;
        }
        if (index == len && res >= 0) {
            return i;
        }
    }
    return -1;
}

巧妙解法,将问题转化才是核心亮点

public int canCompleteCircuit(int[] gas, int[] cost) {
    int res = 0;
    int mincos = Integer.MAX_VALUE;
    int index = 0;
    for (int i = 0; i < gas.length; i++) {
        res += gas[i] - cost[i];
        // 计算出整个过程中油耗最高点,把该点作为最后一个点
        if (res < mincos) {
            mincos = res;
            index = i;
        }
    }
    if (res >= 0) {
        // 返回油耗最高点的下个点作为开始点
        return (index + 1) % gas.length;
    } else {
        return -1;
    }
}

406. 根据身高重建队列

多个条件或者纬度时,一定要先确定好一个纬度,再确定另一个纬度
属于长题目,较复杂,需要理解力,细致,思路清晰,尤其是排序好之后的插入算法,没有想到的化,就十分困难,要梳理关系

public int[][] reconstructQueue(int[][] people) {
    Arrays.sort(people, (t1, t2) -> {
        if (t1[0] == t2[0]) {
            return t1[1] - t2[1];
        } else {
            return t2[0] -t1[0];
        }
    });
    List<int[]> list = new ArrayList<>();
    for (int[] i : people) {
        list.add(i[1], i);
    }
    int i = 0;
    for (int[] j : list) {
        people[i] = j;
        i++;
    }
    return people;
}

List多条件排序

二叉树4种遍历

Map 3 种遍历方法

DFS岛屿类问题

BFS 的使用场景总结:层序遍历、最短路径问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值