LeetCode 2016. 增量元素之间的最大差值 / 553. 最优除法 / 1601. 最多可达成的换楼请求数目(枚举+回溯)

127 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

2016. 增量元素之间的最大差值

2022.2.26 每日一题

题目描述

给你一个下标从 0 开始的整数数组 nums ,该数组的大小为 n ,请你计算 nums[j] - nums[i] 能求得的 最大差值 ,其中 0 <= i < j < n 且 nums[i] < nums[j] 。

返回 最大差值 。如果不存在满足要求的 i 和 j ,返回 -1 。

示例 1:

输入:nums = [7,1,5,4] 输出:4 解释: 最大差值出现在 i = 1 且 j = 2 时,nums[j] - nums[i] = 5 - 1 = 4 。 注意,尽管 i = 1 且 j = 0 时 ,nums[j] - nums[i] = 7 - 1 = 6 > 4 ,但 i > j 不满足题面要求,所以 6 不是有效的答案。

示例 2:

输入:nums = [9,4,3,2] 输出:-1 解释: 不存在同时满足 i < j 和 nums[i] < nums[j] 这两个条件的 i, j 组合。

示例 3:

输入:nums = [1,5,2,10] 输出:9 解释: 最大差值出现在 i = 0 且 j = 3 时,nums[j] - nums[i] = 10 - 1 = 9 。

提示:

n == nums.length 2 <= n <= 1000 1 <= nums[i] <= 10^9

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/ma… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

记录当前最小值,然后记录最大的差值

class Solution {
    public int maximumDifference(int[] nums) {
        int n = nums.length;
        int min = nums[0];
        int diff = -1;
        for(int i = 1; i < n; i++){
            if(nums[i] < min){
                min = nums[i];
            }else if(nums[i] > min){
                diff = Math.max(diff, nums[i] - min);
            }
        }
        return diff;
    }
}

553. 最优除法

2022.2.27 每日一题

题目描述

给定一组正整数,相邻的整数之间将会进行浮点除法操作。例如, [2,3,4] -> 2 / 3 / 4 。

但是,你可以在任意位置添加任意数目的括号,来改变算数的优先级。你需要找出怎么添加括号,才能得到最大的结果,并且返回相应的字符串格式的表达式。你的表达式不应该含有冗余的括号。

示例:

输入: [1000,100,10,2] 输出: "1000/(100/10/2)" 解释: 1000/(100/10/2) = 1000/((100/10)/2) = 200 但是,以下加粗的括号 "1000/((100/10)/2)" 是冗余的, 因为他们并不影响操作的优先级,所以你需要返回 "1000/(100/10/2)"。   其他用例: 1000/(100/10)/2 = 50 1000/(100/(10/2)) = 50 1000/100/10/2 = 0.5 1000/100/(10/2) = 2 说明: 输入数组的长度在 [1, 10] 之间。 数组中每个元素的大小都在 [2, 1000] 之间。 每个测试用例只有一个最优除法解。

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/op… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

要使得除数最小,就是一直除就除数最小

class Solution {
    public String optimalDivision(int[] nums) {
        //要最大的结果,就是要最小的除数,
        //那么怎么才能让后面的除数最小呢,就是一直除就可以了

        int n = nums.length;
        if(n == 1)
            return nums[0] + "";
        if(n == 2)
            return nums[0] + "/" + nums[1];
        String res = nums[0] + "/" + "(";
        for(int i = 1; i < n - 1; i++){
            res = res + nums[i] + "/";
        }
        res = res + nums[n - 1] + ")";

        return res;
    }
}

1601. 最多可达成的换楼请求数目

2022.2.28 每日一题

题目描述

我们有 n 栋楼,编号从 0 到 n - 1 。每栋楼有若干员工。由于现在是换楼的季节,部分员工想要换一栋楼居住。

给你一个数组 requests ,其中 requests[i] = [fromi, toi] ,表示一个员工请求从编号为 fromi 的楼搬到编号为 toi 的楼。

一开始 所有楼都是满的,所以从请求列表中选出的若干个请求是可行的需要满足 每栋楼员工净变化为 0 。意思是每栋楼 离开 的员工数目 等于 该楼 搬入 的员工数数目。比方说 n = 3 且两个员工要离开楼 0 ,一个员工要离开楼 1 ,一个员工要离开楼 2 ,如果该请求列表可行,应该要有两个员工搬入楼 0 ,一个员工搬入楼 1 ,一个员工搬入楼 2 。

请你从原请求列表中选出若干个请求,使得它们是一个可行的请求列表,并返回所有可行列表中最大请求数目。

示例 1:

在这里插入图片描述 输入:n = 5, requests = [[0,1],[1,0],[0,1],[1,2],[2,0],[3,4]] 输出:5 解释:请求列表如下: 从楼 0 离开的员工为 x 和 y ,且他们都想要搬到楼 1 。 从楼 1 离开的员工为 a 和 b ,且他们分别想要搬到楼 2 和 0 。 从楼 2 离开的员工为 z ,且他想要搬到楼 0 。 从楼 3 离开的员工为 c ,且他想要搬到楼 4 。 没有员工从楼 4 离开。 我们可以让 x 和 b 交换他们的楼,以满足他们的请求。 我们可以让 y,a 和 z 三人在三栋楼间交换位置,满足他们的要求。 所以最多可以满足 5 个请求。

示例 2:

在这里插入图片描述 输入:n = 3, requests = [[0,0],[1,2],[2,1]] 输出:3 解释:请求列表如下: 从楼 0 离开的员工为 x ,且他想要回到原来的楼 0 。 从楼 1 离开的员工为 y ,且他想要搬到楼 2 。 从楼 2 离开的员工为 z ,且他想要搬到楼 1 。 我们可以满足所有的请求。

示例 3:

输入:n = 4, requests = [[0,3],[3,1],[1,2],[2,0]] 输出:4

提示:

1 <= n <= 20 1 <= requests.length <= 16 requests[i].length == 2 0 <= fromi, toi < n

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/ma… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

枚举所有情况 + 回溯

class Solution {
    int[] diff;     //每个楼人数变化
    int count;      //处理的请求个数
    int zero;       //人数变化的楼有几个
    int res;
    int n;
    public int maximumRequests(int n, int[][] requests) {
        //这个就相当于形成一个环,看哪几个环最大
        //那么这个该怎么搞呢,因为一个楼可以和多个形成环
        //而所给的n和数组长度也不大,意思是可以暴力做一下
        //但是暴力该怎么做呢,就是遍历所有的成环情况吗

        //判断成环是用拓扑排序,统计入度出度
        //实在有点想不到怎么统计几个环
        //然后就看了官解,官解给出的方法是枚举所有的情况,也就是遍历所有的请求,
        //如果这个请求被考虑,那么就给响应的房间人数发生变化,如果最后所有房间都没有发生变化,就返回当前统计到的请求数
        //如果有楼人数发生了变化,就返回
        
        int l = requests.length;
        this.n = n;
        diff = new int[n];
        zero = n;   //刚开始所有楼人数都没有变化
        dfs(requests, 0);   //处理第几个请求
        return res;
    }

    public void dfs(int[][] requests, int idx){
        //如果遍历到最后一个请求了,同时楼中人数没有发生变化,那么就统计当前变化的请求个数
        if(idx == requests.length){
            if(zero == n){
                res = Math.max(res, count);
            }
            return;
        }
        
        //考虑当前请求
        int z = zero;
        int from =  requests[idx][0];
        int to = requests[idx][1];
        count++;
        
        diff[from]--;
        diff[to]++;
        if(diff[from] == 0)
            zero++;
        else if(diff[from] == -1)
            zero--;
        if(diff[to] == 0)
            zero++;
        else if(diff[to] == 1)
            zero--;
        //如果是自环,那么zero不变
        if(from == to)
            zero = z;
        dfs(requests, idx + 1);
        //回溯
        diff[from]++;
        diff[to]--;
        count--;
        zero = z;
        //不考虑当前请求
        dfs(requests, idx + 1);
    }
}

用二进制表示

class Solution {
    public int maximumRequests(int n, int[][] requests) {
        //用二进制来枚举,就是用每一个二进制位代表当前requests是否被选择
        //如果被选择了,那么更新diff数组,最后查看当前mask下,是否diff数组还是没有变化,
        //如果没有变化,就记录当前结果
        //比回溯那种更简单高效

        int res = 0;
        int l = requests.length;
        int[] diff = new int[n];
        for(int mask = 0; mask < (1 << l); mask++){
            int count = Integer.bitCount(mask);
            if(count <= res)
                continue;
            Arrays.fill(diff, 0);
            //遍历所有为 1 的请求
            for(int i = 0; i < l; i++){
                if(((mask >> i) & 1) != 0){
                    diff[requests[i][0]]--;
                    diff[requests[i][1]]++;
                }
            }

            boolean flag = true;
            for(int t : diff){
                if(t != 0){
                    flag = false;
                    break;
                }
            }
            if(!flag)
                continue;
            res = count;
        }
        return res;
    }
}