LeetCode第102场周赛题解

905. 按奇偶排序数组

  • 题目难度Easy

给定一个非负整数数组 A,返回一个由 A 的所有偶数元素组成的数组,后面跟 A 的所有奇数元素。

你可以返回满足此条件的任何数组作为答案。

示例:

输入:[3,1,2,4]
输出:[2,4,3,1]
输出 [4,2,3,1],[2,4,1,3] 和 [4,2,1,3] 也会被接受。

提示:

  1. 1 <= A.length <= 5000
  2. 0 <= A[i] <= 5000

思路:

没有空间复杂度要求的话,可以开两个数组,一个存储偶数,另一个存储奇数,然后一边遍历原数组一边统计,遍历后把偶数数组和奇数数组连接起来输出即可。

如果要求不另开数组,在原数组上操作的话,那么需要用双指针遍历。双指针遍历有两种方法:一种是双指针同向遍历,初始状态都指在数组左端,后面指针不断加一,遇到偶数就交换到前面去,再把前面指针加一,指导后面指针遍历完数组结束;另外一种是双指针相向遍历,初始状态是第一个指针指在数组左端,第二个指针指在数组右端,当两个指针没有相遇时,右边指针向左寻找偶数,左边指针向右寻找奇数,然后交换指针所指的两个元素,直到两个指针相遇为止。

时间复杂度

空间复杂度

代码:

有辅助数组的算法

class Solution:
    def sortArrayByParity(self, A):
        """
        :type A: List[int]
        :rtype: List[int]
        """
        ans1 = []
        ans2 = []
        for i in A:
            if i % 2 == 0:
                ans1.append(i)
            else:
                ans2.append(i)
        return ans1 + ans2

双指针同向遍历

class Solution:
    def sortArrayByParity(self, A):
        """
        :type A: List[int]
        :rtype: List[int]
        """
        i = 0
        for j in range(len(A)):
            if A[j] % 2 == 0:
                A[i], A[j] = A[j], A[i]
                i += 1
        return A

双指针相向遍历

class Solution(object):
    def sortArrayByParity(self, A):
        """
        :type A: List[int]
        :rtype: List[int]
        """
        
        l = len(A) 
        i, j = 0, l-1
        while i < j:
            while A[i] % 2 == 0 and i < j:
                i += 1
            while A[j] % 2 == 1 and i < j:
                j -= 1
            A[i], A[j] = A[j], A[i]
                    
        return A

904. 水果成篮

  • 题目难度Medium

在一排树中,第 i 棵树产生 tree[i] 型的水果。
你可以从你选择的任何树开始,然后重复执行以下步骤:

  1. 把这棵树上的水果放进你的篮子里。如果你做不到,就停下来。
  2. 移动到当前树右侧的下一棵树。如果右边没有树,就停下来。

请注意,在选择一颗树后,你没有任何选择:你必须执行步骤 1,然后执行步骤 2,然后返回步骤 1,然后执行步骤 2,依此类推,直至停止。

你有两个篮子,每个篮子可以携带任何数量的水果,但你希望每个篮子只携带一种类型的水果。
用这个程序你能收集的水果总量是多少?

示例 1:

输入:[1,2,1]
输出:3
解释:我们可以收集 [1,2,1]。

示例 2:

输入:[0,1,2,2]
输出:3
解释:我们可以收集 [1,2,2].
如果我们从第一棵树开始,我们将只能收集到 [0, 1]。

示例 3:

输入:[1,2,3,2,2]
输出:4
解释:我们可以收集 [2,3,2,2].
如果我们从第一棵树开始,我们将只能收集到 [1, 2]。

示例 4:

输入:[3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:我们可以收集 [1,2,1,1,2].
如果我们从第一棵树或第八棵树开始,我们将只能收集到 4 个水果。

提示:

  1. 1 <= tree.length <= 40000
  2. 0 <= tree[i] < tree.length

思路:

顺序遍历或者倒序遍历都可以。以从后往前的倒序遍历为例,用fruit数组表示两个水果种类代号,将tree[len(tree)-1]加入到fruit中,然后指针从最后一棵树开始,往前遍历寻找另一种不同水果。如果找不到,说明只有一种水果,直接返回len(tree)。如果找到了,将第二种水果加入到fruit中,用startstop数组表示两个水果在区间的起始位置和结束位置,则每扫描一个区间,最大长度为max(stop)-min(start),继续扫描下个区间,这时要判断篮子里保存哪个水果,所以需要比较两个水果的起始位置,保留start值较小的那种类型的水果,将另一种水果用当前指针新发现的水果替换,保留水果的stop值还要用被替换水果的start值更新,即stop[0] = min(stop[0], start[1] - 1)

时间复杂度
空间复杂度

代码:

倒序遍历

class Solution:
    def totalFruit(self, tree):
        """
        :type tree: List[int]
        :rtype: int
        """
        l_tree = len(tree)

        if l_tree <= 2:
            return l_tree

        ans = 2

        l = l_tree - 1
        fruit = [tree[l], tree[l]]
        start = [l, l]
        stop = [l, l]

        # find the other fruit
        i = l
        while i >= 0 and tree[i] == fruit[0]:
            i -= 1
        # only one kind of fruit
        if i < 0:
            return l_tree
        else:
            fruit[1] = tree[i]
            start[0] = i + 1
            start[1] = i
            stop[1] = i

        i -= 1
        while i >= 0:
            while i >= 0:
                if tree[i] == fruit[0]:
                    start[0] = i
                elif tree[i] == fruit[1]:
                    start[1] = i
                else:
                    break
                i -= 1

            ans = max(ans, stop[0] - i)
            if start[0] > start[1]:
                fruit = fruit[::-1]
                start = start[::-1]
                stop = stop[::-1]

            stop[0] = min(stop[0], start[1] - 1)
            fruit[1] = tree[i]
            start[1] = i
            stop[1] = i
        
        ans = max(ans, stop[0] - i)
        return ans

顺序遍历

class Solution:
    def totalFruit(self, tree):
        """
        :type tree: List[int]
        :rtype: int
        """
        ans = 0
        to_end = 1
        start = 0
        found = {tree[0]}
        for i in range(1, len(tree)):
            if tree[i] in found:
                to_end += 1
            elif len(found) < 2:
                found.add(tree[i])
                to_end += 1
            else:
                ans = max(to_end, ans)
                to_end = i - start + 1
                found = {tree[i], tree[i-1]}
            # 这里更新两种水果的分界点
            if tree[i] != tree[i-1]:
                start = i
        return max(to_end, ans)

907. 子数组的最小值之和

  • 题目难度Medium

给定一个整数数组 A,找到 min(B) 的总和,其中 B 的范围为 A 的每个(连续)子数组。

由于答案可能很大,因此返回答案模 10^9 + 7

示例:

输入:[3,1,2,4]
输出:17
解释:
子数组为 [3],[1],[2],[4],[3,1],[1,2],[2,4],[3,1,2],[1,2,4],[3,1,2,4]。 
最小值为 3,1,2,4,1,1,2,1,1,1,和为 17。

提示:

  1. 1 <= A <= 30000
  2. 1 <= A[i] <= 30000

思路:

考虑从A中的每个元素A[i],如果求出包含A[i]并以A[i]为最小元素的所有子数组个数n[i],则元素A[i]对答案ans的贡献为n[i]*A[i],那么我们可以先求包含A[i]并以A[i]为最小元素的最长子数组,如果A[i]左边第一个小于A[i]的元素为A[left]A[i]右边第一个小于A[i]的元素为A[right],则包含A[i]并以A[i]为最小元素的最长子数组为A[left+1:right],满足以A[i]为最小元素的所有子数组个数n[i] = (i-left)*(right-i)。我们用left[i]表示A[i]左边第一个小于A[i]元素的位置,用right[i]表示A[i]右边第一个小于A[i]元素的位置,left数组初始值为-1right数组初始值为len(A),求解leftright可以用单调栈来实现,可以两遍遍历,也可以一遍遍历,更优化的写法还可以一边遍历一边求解ans

时间复杂度

空间复杂度

代码:

class Solution:
    def sumSubarrayMins(self, A):
        """
        :type A: List[int]
        :rtype: int
        """
        len_A = len(A)
        if len_A == 0:
            return 0
        if len_A == 1:
            return A[0]
        
        ans = 0
        left = [0] * len_A
        right = [0] * len_A
        
        stack = []
        for i in range(len_A):
            while stack and A[stack[-1]] > A[i]:
                stack.pop()
            if not stack:
                left[i] = -1
            else:
                left[i] = stack[-1]
            stack.append(i)
        
        stack = []
        for i in range(len_A - 1, -1, -1):
            while stack and A[stack[-1]] >= A[i]:
                stack.pop()
            if not stack:
                right[i] = len_A
            else:
                right[i] = stack[-1]
            stack.append(i)
        
        for i in range(len_A):
            ans += (i - left[i]) * (right[i] - i) * A[i]
            ans %= 1000000007
        return ans

一遍遍历

class Solution:
    def sumSubarrayMins(self, A):
        """
        :type A: List[int]
        :rtype: int
        """
        ans = 0
        A = [float('-inf')] + A + [float('-inf')]
        stack = []
        for i, a in enumerate(A):
            while stack and A[stack[-1]] > a:
                cur = stack.pop()
                ans += A[cur] * (i-cur) * (cur-stack[-1])
            stack.append(i)
        return ans % (10**9 + 7)

906. 超级回文数

  • 题目难度Hard

如果一个正整数自身是回文数,而且它也是一个回文数的平方,那么我们称这个数为超级回文数。

现在,给定两个正整数 LR (以字符串形式表示),返回包含在范围 [L, R] 中的超级回文数的数目。

示例:

输入:L = "4", R = "1000"
输出:4
解释:
4,9,121,以及 484 是超级回文数。
注意 676 不是一个超级回文数: 26 * 26 = 676,但是 26 不是回文数。

提示:

  1. 1 <= len(L) <= 18
  2. 1 <= len(R) <= 18
  3. LR 是表示 [1, 10^18) 范围的整数的字符串。
  4. int(L) <= int(R)

思路:

从1产生回文数,把产生的回文数平方,判断平方后是不是回文数并在[L, R]内。

由于超级回文数的个数十分有限,所以也可以打表解决。

时间复杂度

空间复杂度

代码:

class Solution:
    def superpalindromesInRange(self, L, R):
        """
        :type L: str
        :type R: str
        :rtype: int
        """
        def is_circle(num):
            s = str(num)
            return s == s[::-1]

        def create_circle(num):
            s = str(num)
            first = int(s + s[::-1])
            second = int(s[:-1] + s[::-1])
            return first, second

        l = int(math.sqrt(int(L)))
        r = int(math.sqrt(int(R))) + 1
        # print(l, r)
        ans = 0
        for num in range(1, 100000):
            # print(num)
            big, small = create_circle(num)
            # print(big, small)
            if l <= small < r:
                if is_circle(small * small):
                    ans += 1
            if l <= big < r:
                if is_circle(big * big):
                    ans += 1
            if small > r:
                break
        return ans

打表

class Solution:

    DATA2 = [1,
 4,
 9,
 121,
 484,
 10201,
 12321,
 14641,
 40804,
 44944,
 1002001,
 1234321,
 4008004,
 100020001,
 102030201,
 104060401,
 121242121,
 123454321,
 125686521,
 400080004,
 404090404,
 10000200001,
 10221412201,
 12102420121,
 12345654321,
 40000800004,
 1000002000001,
 1002003002001,
 1004006004001,
 1020304030201,
 1022325232201,
 1024348434201,
 1210024200121,
 1212225222121,
 1214428244121,
 1232346432321,
 1234567654321,
 4000008000004,
 4004009004004,
 100000020000001,
 100220141022001,
 102012040210201,
 102234363432201,
 121000242000121,
 121242363242121,
 123212464212321,
 123456787654321,
 400000080000004,
 10000000200000001,
 10002000300020001,
 10004000600040001,
 10020210401202001,
 10022212521222001,
 10024214841242001,
 10201020402010201,
 10203040504030201,
 10205060806050201,
 10221432623412201,
 10223454745432201,
 12100002420000121,
 12102202520220121,
 12104402820440121,
 12122232623222121,
 12124434743442121,
 12321024642012321,
 12323244744232321,
 12343456865434321,
 12345678987654321,
 40000000800000004,
 40004000900040004,
 1000000002000000001,
 1000220014100220001,
 1002003004003002001,
 1002223236323222001,
 1020100204020010201,
 1020322416142230201,
 1022123226223212201,
 1022345658565432201,
 1210000024200000121,
 1210242036302420121,
 1212203226223022121,
 1212445458545442121,
 1232100246420012321,
 1232344458544432321,
 1234323468643234321]
    def superpalindromesInRange(self, L, R):
        """
        :type L: str
        :type R: str
        :rtype: int
        """

        start = int(L)
        end = int(R)
        index = 0
        for i in self.DATA2:
            if end>=i>=start:
                index+=1
        return index

你可能感兴趣的:(LeetCode第102场周赛题解)