leetcode 第216场周赛总结

leetcode第216场周赛总结

刷题也有一段时间了,准备开始记录一下自己参加周赛的过程,上周因为礼拜天有事没办法直接参与。于是只能搞一下虚拟竞赛尝试一下,没想到这周的题比较简单,错过了一个刷分的机会[狗头]。从这周开始,有时间的话记录一下自己的周赛过程和当时的想法。

第一题

检查两个字符串数组是否相等

题目链接: link.
给你两个字符串数组 word1 和 word2 。如果两个数组表示的字符串相同,返回 true ;否则,返回 false 。

数组表示的字符串 是由数组中的所有元素 按顺序 连接形成的字符串。
在这里插入图片描述
解题思路:
最开始我还以为是任意顺序的,还想了一下怎么写。后来看到是以数组的原始顺序,那么只要将字符数组内的数据按照顺序连接起来,再比较就好了。

class Solution {
    public boolean arrayStringsAreEqual(String[] word1, String[] word2) {
        StringBuilder s1 = new StringBuilder();
        for(String s : word1){
            s1.append(s);
        }
        StringBuilder s2 = new StringBuilder();
        for(String s : word2){
            s2.append(s);
        }
        return s1.toString().equals(s2.toString());
    }
}

第二题

具有给定数值的最小字符串

题目链接: link.
小写字符 的 数值 是它在字母表中的位置(从 1 开始),因此 a 的数值为 1 ,b 的数值为 2 ,c 的数值为 3 ,以此类推。

字符串由若干小写字符组成,字符串的数值 为各字符的数值之和。例如,字符串 “abe” 的数值等于 1 + 2 + 5 = 8 。

给你两个整数 n 和 k 。返回 长度 等于 n 且 数值 等于 k 的 字典序最小 的字符串。

注意,如果字符串 x 在字典排序中位于 y 之前,就认为 x 字典序比 y 小,有以下两种情况:

x 是 y 的一个前缀;
如果 i 是 x[i] != y[i] 的第一个位置,且 x[i] 在字母表中的位置比 y[i] 靠前。
在这里插入图片描述
解题思路:
很明显的贪心问题。

总结一下贪心问题的解题秘诀:
已经解决的问题 是可以延续到后面以利用的条件。
未来的任何情况 都无需提前考虑。

对于这道题来说,因为是要求最小的字典序,所以我们从最后一位开始遍历,因为最后一位对于整个字符的影响最小。我们不考虑之后怎么解,假定当前情况求最佳,如果K充分大(大于26),就把当前位置为z,如果不够。当前所有的k都消耗到当前位置,然后其他位置置为a.

class Solution {
    public String getSmallestString(int n, int k) {
        int[] arr = new int[n];
        k = k - n;
        for(int i = n - 1;i >= 0;i--){
            if(k >= 25){
                k -= 25;
                arr[i] += 25;
            }else{
                arr[i] += k;
                break;
            }
        }
        StringBuilder s = new StringBuilder();
        for(int i = 0;i<n;i++){
            char c = (char)('a' + arr[i]);
            s.append(c);
        }
        return s.toString();
    }
}

第三题

生成平衡数组的方案数

题目链接: link.
给你一个整数数组 nums 。你需要选择 恰好 一个下标(下标从 0 开始)并删除对应的元素。请注意剩下元素的下标可能会因为删除操作而发生改变。

比方说,如果 nums = [6,1,7,4,1] ,那么:

选择删除下标 1 ,剩下的数组为 nums = [6,7,4,1] 。
选择删除下标 2 ,剩下的数组为 nums = [6,1,4,1] 。
选择删除下标 4 ,剩下的数组为 nums = [6,1,7,4] 。
如果一个数组满足奇数下标元素的和与偶数下标元素的和相等,该数组就是一个 平衡数组 。

请你返回删除操作后,剩下的数组 nums 是 平衡数组 的 方案数 。
在这里插入图片描述
解题思路:
首先,这道题要求判定两部分数组(奇数索引和偶数索引)的和,我们知道当需要求一个数组[…]中某一段的和,可以用前缀和的知识。
我们抛开删除这一个操作,仅仅只要求这个数组中[left…right]这个区间中奇数索引和偶数索引数的和,是不是只要用sum([0…rigth]) - sum([0…left])就可以了,然后就是删除操作:
假设删除的索引为index
[。。。。。。index。。。。。。]
则[。。。。。index - 1]这个区间的奇偶性质是不变的
而[index + 1。。。。。。]这个区间的奇偶性质翻转(因为索引都减去了1)

于是我们针对每一个点都求出他们前后两个区间的奇数索引和偶数索引数的和,再比较就可以了

class Solution {
    public int waysToMakeFair(int[] nums) {
        if(nums.length == 1) return 1;
        
    
        int[][] sum = new int[nums.length][2];
        sum[0][0] = nums[0];//偶数位和
        sum[0][1] = 0;//奇数位和
        for(int i = 1;i<nums.length;i++){ //动态规划求奇数和偶数的和
            if(i % 2 == 0){
                sum[i][0] = sum[i - 1][0] + nums[i];
                sum[i][1] = sum[i - 1][1];
            }else{
                sum[i][0] = sum[i - 1][0];
                sum[i][1] = sum[i - 1][1] + nums[i];
            }
        }
        int ans = 0;
        int len = nums.length;
        if(sum[len - 1][0] - nums[0] == sum[len - 1][1]) ans += 1;
        for(int i = 1;i<len;i++){
            int sumE0 = sum[len - 1][0] - sum[i][0]; // 当前索引之前的 奇数索引数的和
            int sumE1 = sum[len - 1][1] - sum[i][1]; // 当前索引之前的 偶数索引数的和
            int sumB0 = sum[i - 1][0];               // 当前索引之后的 奇数索引数的和
            int sumB1 = sum[i - 1][1];               // 当前索引之后的 偶数索引数的和
            
            int sum0 = sumB0 + sumE1;//全部奇数索引之和
            int sum1 = sumB1 + sumE0;//全部偶数索引之和
            if(sum0 == sum1){
                ans += 1;
            }
        }
        return ans;
    }
}

第四题

完成所有任务的最少初始能量

题目链接: link.
给你一个任务数组 tasks ,其中 tasks[i] = [actuali, minimumi] :

actuali 是完成第 i 个任务 需要耗费 的实际能量。
minimumi 是开始第 i 个任务前需要达到的最低能量。
比方说,如果任务为 [10, 12] 且你当前的能量为 11 ,那么你不能开始这个任务。如果你当前的能量为 13 ,你可以完成这个任务,且完成它后剩余能量为 3 。

你可以按照 任意顺序 完成任务。

请你返回完成所有任务的 最少 初始能量。
在这里插入图片描述
解题思路:
这道题在写的时候就感觉要用贪心。
不过最开始想到的是先按照最低能量minimumi 排序,再贪心。写完之后发现不是,我自己的思路是这样的:
因为每次要满足最低能量minimumi ,然后要消耗掉能量actuali。则这次的minimumi - actuali就是你要付出的额外开销,当我们需要最小的总能量时,首先满足总能量要大于所有actuali的和,而且每一次都有富余的能量去满足额外的开销。而你的总能量是不断下降的,我们就要先去做那些额外开销大的任务,因为此时的能量数总是可以满足开销 ,而不用添加额外的能量。等到后面能能量不足时,也只要弥补开销比较小的任务即可。

class Solution {
    public int minimumEffort(int[][] tasks) {
        Arrays.sort(tasks, new Comparator<int[]>(){
            @Override
            public int compare(int[] o1,int[] o2){
                if(o1[1] - o1[0] == o2[1] - o2[0]){
                    return o2[1] - o1[1]; // 这一步好像不用,我加上了按照minimumi 排序
                }else{
                    return (o2[1] - o2[0]) - (o1[1] - o1[0]);
                }
            }
        });
        int sum = 0;
        for(int i = 0;i<tasks.length;i++){
            sum += tasks[i][0];
        }
        int c_sum = sum;
        for(int i = 0;i<tasks.length;i++){
            if(c_sum < tasks[i][1]){
                sum += (tasks[i][1] - c_sum);
                c_sum = tasks[i][1];
            }
            c_sum -= tasks[i][0];
        }
        return sum;
    }
}

总结

这次2,3道问题都是贪心求解,不像之前最后一道要么是图要么是树(我一般都写不出来[狗头])。
总的来说,贪心问题还是没有动态规划和各种图的问题难,只要紧紧抓住当前最优即可

文中的题目描述和图片均来自于leetcode
链接: link.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值