LeetCode笔记:Weekly Contest 227 比赛记录

  • LeetCode笔记:Weekly Contest 227
    • 0. 赛后总结
    • 1. 题目一
      • 1. 解题思路
      • 2. 代码实现
    • 2. 题目二
      • 1. 解题思路
      • 2. 代码实现
    • 3. 题目三
      • 1. 解题思路
      • 2. 代码实现
    • 4. 题目四
      • 1. 解题思路
      • 2. 代码实现
      • 3. 算法优化

0. 赛后总结

这次的比赛其实因为加班的关系没有参加,然后也不想做模拟比赛了,就随便自己做了做,结果发现,还好我没有参加这次比赛,各种马失前蹄,错的各种离谱,如果参加的话估计又是要直接跌到3000名的样子了……

唉,代码之道还是任重而道远啊……

1. 题目一

给出题目一的试题链接如下:

  • 1752. Check if Array Is Sorted and Rotated

1. 解题思路

这一题的解题思路挺直白的,因为原数组会是一个单调非减的数组,因此,只要确保以下两点即可作为充要条件:

  1. 至多数组中只会出现一个下降点;
  2. 数组的最后一个元素一定不大于数组的第一个元素。

对此进行判断即可。

2. 代码实现

给出python代码实现如下:

class Solution:
    def check(self, nums: List[int]) -> bool:
        n = len(nums)
        for i in range(n-1):
            if nums[i] > nums[i+1]:
                return nums[-1] <= nums[0] and all(nums[j] <= nums[j+1] for j in range(i+1, n-1))
        return True

提交代码评测得到:耗时32ms,占用内存14.3MB。

2. 题目二

给出题目二的试题链接如下:

  • 1753. Maximum Score From Removing Stones

1. 解题思路

这一题我一开始想岔了,用动态规划进行了解决,虽然提交也是过了,但是执行效率实在是惨不忍睹。

其实仔细分析一下这道题,这题其实挺直接的。

首先,我们将a,b,c按照从小到大顺序排列,假设a+b<=c,那么显然答案就是a+b

如果a+b>c,那么,我们只需要先对a,b进行一些内部消耗,使之满足a' + b' <= c,即可重新套用上述的公式。

2. 代码实现

给出python代码实现如下:

class Solution:
    def maximumScore(self, a: int, b: int, c: int) -> int:
        a, b, c = sorted([a,b,c])
        if a+b <= c:
            return a+b
        else:
            return (a+b-c) // 2 + c

提交代码评测得到:耗时24ms,占用内存14.4MB。

3. 题目三

给出题目三的试题链接如下:

  • 1754. Largest Merge Of Two Strings

1. 解题思路

这一题也是典型的题目简单但是想岔了类型。。。

说白了这道题只要根据题意进行逐次操作即可,但是需要注意的是,如果两个字符串的首字符相同时,会遇到一定的问题,所以我当时想着就是用动态规划,然后就各种超时……

事实上,我们没有必要只比首字符,直接对两个字符串进行比较就行了,因为当首字符相同时,我们总是希望尽可能更早的将较大的元素放到前方,这个和字符串的比较是一致的,因此这道题就瞬秒了……

2. 代码实现

给出python代码实现如下:

class Solution:
    def largestMerge(self, word1: str, word2: str) -> str:
        i, j, n, m = 0, 0, len(word1), len(word2)
        res = ""
        while i < n and j < m:
            if word1[i:] < word2[j:]:
                res += word2[j]
                j += 1
            else:
                res += word1[i]
                i += 1
        res += word1[i:]
        res += word2[j:]
        return res

提交代码评测得到:耗时84ms,占用内存14.6ms。

4. 题目四

我们给出题目四的试题链接如下:

  • 1755. Closest Subsequence Sum

1. 解题思路

这一题坦率地说没啥好的思路,直接的一个想法就是动态规划,但是如果暴力求解的话显然会遇到超时问题,因此,我们需要考虑一定的剪枝。

我们考虑如下几种情况:

  1. 如果当前候选数字之和刚好等于目标,则直接返回结果即可;
  2. 如果当前候选数字之和小于目标值,且候选数字全为正数,那么不可能通过删减候选数字的方式获得更接近目标值的结果;
  3. 如果当前候选数字之和大于目标值,且候选数字全为负数,那么不可能通过删减候选数字的方式获取更接近目标值的结果;

而对于其他的情况,我们只需要考虑如下情况即可:

  1. 如果当前候选数字的和大于目标值,那么我们考虑候选集中某一个正数被保留或者删除的情况;
  2. 如果当前候选数字的和小于目标值,那么我们考虑候选集中某一个负数被保留或者删除的情况;

综上,我们即可以给出最终的代码实现。

2. 代码实现

给出python代码实现如下:

class Solution:
    def minAbsDifference(self, nums: List[int], goal: int) -> int:
        res = goal
        nums = sorted(nums)
        n = len(nums)
        s = sum(nums)
        
        @lru_cache(None)
        def dp(i, j, s):
            if s == goal:
                return 0
            elif i > j:
                return abs(goal-s)
            elif s > goal:
                if nums[j] <= 0:
                    return abs(goal - s)
                return min(dp(i, j-1, s-nums[j]), dp(i, j-1, s))
            else:
                if nums[i] >= 0:
                    return abs(goal - s)
                return min(dp(i+1, j, s-nums[i]), dp(i+1, j, s))
            
        return dp(0, n-1, s)

提交代码评测得到:耗时3068ms,占用内存679.2MB。

当前最优的代码实现耗时仅36ms,有近两个量级的性能提升。

因此,下面我们来看一下他们的算法思路。

3. 算法优化

看了一下当前最优的算法实现,发现他们somehow将算法复杂度直接退化到了 O ( N ) O(N) O(N)的程度。

但是坦率说,他们算法的内核没有完全看懂,所以这里就仅仅摘录在下方供读者参考,如果有看明白的请务必在评论区指导一二,万分感谢。

class Solution:
    def minAbsDifference(self, nums: List[int], goal: int) -> int:
        res = inf
        n = len(nums)
        nums.sort(key = lambda x:-abs(x))
        leftmax = [0] * n
        leftmin = [0] * n
        pos = neg = 0
        for i in range(n-1, -1, -1):
            if nums[i] > 0:
                pos += nums[i]
            else:
                neg += nums[i]
            leftmax[i] = pos
            leftmin[i] = neg

        def backtracking(cur, index):
            nonlocal res
            nonlocal goal
            if res == 0:
                return
            ncur = cur + nums[index]
            if abs(ncur - goal) < res:
                res = abs(ncur - goal)
            if abs(cur - goal) < res:
                res = abs(cur - goal)
            if index == len(nums) - 1:
                return
            x,y = leftmin[index + 1], leftmax[index+1]
            if ncur + x < goal < ncur + y:
                backtracking(ncur, index + 1)
            else:
                res = min(res, abs(ncur + x - goal), abs(ncur + y - goal))
            if cur + x < goal < cur + y:
                backtracking(cur, index + 1)
            else:
                res = min(res, abs(cur + x - goal), abs(cur + y - goal))
                
        backtracking(0, 0)
        return res

你可能感兴趣的:(leetcode笔记,算法,leetcode,python,数据结构)