美文网首页
LeetCode第102场周赛题解

LeetCode第102场周赛题解

作者: 独孤岳 | 来源:发表于2019-02-01 15:35 被阅读0次

    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

    思路:

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

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

    时间复杂度O(N)

    空间复杂度O(1)

    代码:

    有辅助数组的算法

    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)

    时间复杂度O(N)
    空间复杂度O(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

    时间复杂度O(N)

    空间复杂度O(N)

    代码:

    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]内。

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

    时间复杂度O(\sqrt{N})

    空间复杂度O(1)

    代码:

    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场周赛题解

          本文链接:https://www.haomeiwen.com/subject/eujdsqtx.html