leetcode 11.12-11.18

每日一题922. 按奇偶排序数组 II

给定一个非负整数数组 A, A 中一半整数是奇数,一半整数是偶数。

对数组进行排序,以便当 A[i] 为奇数时,i 也是奇数;当 A[i] 为偶数时, i 也是偶数。

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

示例:
输入:[4,2,5,7]
输出:[4,5,2,7]
解释:[4,7,2,5],[2,5,4,7],[2,7,4,5] 也会被接受。

class Solution:
    def sortArrayByParityII(self, A: List[int]) -> List[int]:
        """
        双指针解法:用i,j下标指示A中偶数和奇数下标。 
        如果偶数下标里面的值出现奇数,就在奇数下标中找到偶数与其互换。
        """
        j = 1
        for i in range(0, len(A), 2):
            if A[i] % 2 == 1:
                while A[j] % 2 == 1:
                    j = j + 2
                A[i], A[j] = A[j], A[i]
        return A

1047. 删除字符串中的所有相邻重复项

给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例:
输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。

class Solution:
    def removeDuplicates(self, S: str) -> str:
        '''
        栈描述,新字符与栈顶部相同则pop.不同append
        '''
        Stack = []
        for ch in S:
            if Stack and ch == Stack[-1]:
                Stack.pop()
            else:
                Stack.append(ch)
        return ''.join(Stack)

每日一题 328. 奇偶链表

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。

示例 1:
输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL

示例 2:
输入: 2->1->3->5->6->4->7->NULL
输出: 2->3->6->7->1->5->4->NULL

说明:
应当保持奇数节点和偶数节点的相对顺序。
链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def oddEvenList(self, head: ListNode) -> ListNode:
        '''
        思路为双链表,分别为奇数节点链表oddhead,和偶数节点链表evenhead.
        odd表示为奇数节点遍历位置,even为偶数节点遍历位置。
        如果even为空,或者even.next 为空结束循环
        '''
        if not head:
            return head
        oddhead, evenhead = head, head.next
        odd, even = oddhead, evenhead
        while even and even.next:
            odd.next = odd.next.next
            even.next = even.next.next
            odd = odd.next
            even = even.next
        odd.next = evenhead
        return oddhead

1416. 恢复数组

某个程序本来应该输出一个整数数组。但是这个程序忘记输出空格了以致输出了一个数字字符串,我们所知道的信息只有:数组中所有整数都在 [1, k] 之间,且数组中的数字都没有前导 0 。

给你字符串 s 和整数 k 。可能会有多种不同的数组恢复结果。

按照上述程序,请你返回所有可能输出字符串 s 的数组方案数。

由于数组方案数可能会很大,请你返回它对 10^9 + 7 取余 后的结果。

示例 1:
输入:s = "1000", k = 10000
输出:1
解释:唯一一种可能的数组方案是 [1000]

示例 2:
输入:s = "1000", k = 10
输出:0
解释:不存在任何数组方案满足所有整数都 >= 1 且 <= 10 同时输出结果为 s 。

示例 3:
输入:s = "1317", k = 2000
输出:8
解释:可行的数组方案为 [1317],[131,7],[13,17],[1,317],[13,1,7],[1,31,7],[1,3,17],[1,3,1,7]

示例 4:
输入:s = "2020", k = 30
输出:1
解释:唯一可能的数组方案是 [20,20] 。 [2020] 不是可行的数组方案,原因是 2020 > 30 。 [2,020] 也不是可行的数组方案,因为 020 含有前导 0 。

示例 5:
输入:s = "1234567890", k = 90
输出:34

class Solution:
    def numberOfArrays(self, s: str, k: int) -> int:
        '''
        dp思路dp[i] 表示s[i:]能组成的结果.
        我们用str'1317' 举例,反向历遍dp。 当i = 3 表示s[3] = '7' 的所有输出可能概率。
        当s[3] 表示的值大于k 那么这一系列的结果就都会大于k 返回0, dp[3] = 0 
        当s[3] 表示的值小于k 那么就表示s[3:4]'7' 这个字符 加上空字符''的结果. 所以dp[3] = dp[4]
        空字符''返回结果为1, dp[4] = 1. 
        当s[2] 表示的值大于k 那么这一系列的结果就都会大于k 返回0, dp[2] = 0 
        当s[2] 表示的值小于k 那么表示s[2:3]'1' 这个字符 加上s[3]'7' 这个字符的结果 dp[2] = dp[2] + dp[3]
        同在s[2]这个节点下, s[2:4]'17' 表示的值小于k 这个字符 加上空字符'' 的结果 dp[2] = dp[2] + dp[4] 
        最终s[2] 的所有情况为 dp[2] = dp[2] + dp[3] + dp[4] .初始dp[2] = 0. 换算为 dp[2] = dp[3] + dp[4] 
        假设同在s[2]这个节点下,s[2:4]'17' 这个字符的值大于k, 则s[2:4]'17' 情况下 dp[2] = 0
        最终s[2] 的所有情况为 dp[2] = dp[2] + dp[3].初始dp[2] = 0. 换算为 dp[2] = dp[3]
        以此类推 直到算出s[0] 的所有情况dp[0]
        '''
        n, mod = len(s), 1000000007
        dp = [0] * (n + 1)
        dp[-1] = 1
        print(s[2:4])
        for i in range(len(s) - 1 , -1, -1):
            if s[i] == '0': 
                continue
            cur = 0
            for j in range(i + 1, n + 1):
                cur = cur * 10 + int(s[j - 1]) 
                if cur > k:
                    break
                dp[i] = (dp[i] + dp[j]) % mod
        return dp[0]

每日一题1122. 数组的相对排序

给你两个数组,arr1arr2

  • arr2 中的元素各不相同
  • arr2 中的每个元素都出现在 arr1

arr1 中的元素进行排序,使 arr1 中项的相对顺序和 arr2 中的相对顺序相同。未在 arr2 中出现过的元素需要按照升序放在 arr1 的末尾。

示例:

输入:arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6]
输出:[2,2,2,1,4,3,3,9,6,7,19]

class Solution:
    def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
        '''
        思路采用两个list, 其中一个list, num表示arr2中每个数在arr1中出现的次数,
        另一个r2, 表示所有arr1中没有出现在arr2中的数。
        所以出现在arr2中的数排序, r1 应该为arr2对应的值重复num中对应位置的次数
        最终排序为r1 + sorted(r2)
        '''
        num = [0] * len(arr2)
        r1, r2 = [], []
        for ch in arr1:
            if ch in arr2:
                num[arr2.index(ch)] += 1
            else:
                r2.append(ch)
        for i in range(len(arr2)):
            r1.append([arr2[i]] * num[i])
        r1 = sum(r1, []) # 数据降成一维
        return r1 + sorted(r2)

每日一题402. 移掉K位数字

给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。

注意:
num 的长度小于 10002 且 ≥ k。
num 不会包含任何前导零。

示例 1 :
输入: num = "1432219", k = 3
输出: "1219"
解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。

示例 2 :
输入: num = "10200", k = 1
输出: "200"
解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。

示例 3 :
输入: num = "10", k = 2
输出: "0"
解释: 从原数字移除所有的数字,剩余为空就是0。

class Solution:
    def removeKdigits(self, num: str, k: int) -> str:
        '''
        我们先来理清思路,首先我们确定一点的是,如果要判定123abc 和123def 谁大
        只需要从第一个不同的数字判断,如果a>d 则123abc大。
        对于123abc,我们只需要判断3和a谁大,如果a更大,那么保留a继续找,如果3更大,
        我们就需要把3删掉,继续判断2和a谁大。如此删除k个数即可
        '''
        if len(num) <= k:
            return '0'
        stack = []
        remain = len(num) - k 
        for ch in num:
            while k and stack and stack[-1] > ch:
                stack.pop()
                k = k - 1
            stack.append(ch)
        # int()主要用来去除开头的数字0
        return str(int(''.join(stack[:remain])))

每日一题406. 根据身高重建队列

假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)表示,其中h是这个人的身高,k是排在这个人前面且身高大于或等于h的人数。 编写一个算法来重建这个队列。

注意:
总人数少于1100人。

示例
输入:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
输出:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]

class Solution:
    def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
        '''
        (h, k)
        首先按照身高从高往低排序,保证后面的身高永远小于等于前面的,那么前面的个数就是k。
        res=[]
        如果新加的(h, k)中的k等于res的长度,那么我们就append就行,因为k就表示前面的数大于当前h的长度
        如果小于,那么就在res这个数组的k位置插入(h, k), 表示前面的k个数都是大于当前的h
        '''
        people = sorted(people, key = lambda x: (-x[0], x[1]))
        res = []
        for p in people:
            if len(res) == p[1]:
                res.append(p)
            else:
                res.insert(p[1], p)
        return res

每日一题1030. 距离顺序排列矩阵单元格

给出 RC 列的矩阵,其中的单元格的整数坐标为 (r, c),满足 0 <= r < R0 <= c < C

另外,我们在该矩阵中给出了一个坐标为 (r0, c0) 的单元格。

返回矩阵中的所有单元格的坐标,并按到 (r0, c0) 的距离从最小到最大的顺序排,其中,两单元格(r1, c1)(r2, c2) 之间的距离是曼哈顿距离,|r1 - r2| + |c1 - c2|。(你可以按任何满足此条件的顺序返回答案。)

示例 1:
输入:R = 1, C = 2, r0 = 0, c0 = 0
输出:[[0,0],[0,1]]
解释:从 (r0, c0) 到其他单元格的距离为:[0,1]

示例 2:
输入:R = 2, C = 2, r0 = 0, c0 = 1
输出:[[0,1],[0,0],[1,1],[1,0]]
解释:从 (r0, c0) 到其他单元格的距离为:[0,1,1,2]
[[0,1],[1,1],[0,0],[1,0]] 也会被视作正确答案。

class Solution:
    def allCellsDistOrder(self, R: int, C: int, r0: int, c0: int) -> List[List[int]]:
        '''
        存储所有可能的坐标,按照曼哈顿距离排序
        '''
        ref = [(r, c) for r in range(R) for c in range(C)]
        ref.sort(key = lambda x: abs(x[0] - r0) + abs(x[1] - c0))
        return ref

每日一题134. 加油站

在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i]升。

你有一辆油箱容量无限的的汽车,从第* i 个加油站开往第 i+1 *个加油站需要消耗汽油 cost[i]升。你从其中的一个加油站出发,开始时油箱为空。

如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。

说明:

  • 如果题目有解,该答案即为唯一答案。
  • 输入数组均为非空数组,且长度相同。
  • 输入数组中的元素均为非负数。

示例 1:

输入:
gas = [1,2,3,4,5]
cost = [3,4,5,1,2]

输出: 3

解释:
从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油
开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油
开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油
开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油
开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油
开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。
因此,3 可为起始索引。

class Solution:
    def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
        '''
        暴力解法, 从第一个加油站一直到最后一个加油站查询是否有符合的加油站
        '''
        # 数组保存当前加油站跑到下一个加油站,油量的增减情况
        rem = list(map(lambda x: x[0]-x[1], zip(gas, cost))) * 2
        n = len(gas)
        for i in range(n):
            # 循环历变加油站,每次的初始油量为0
            res = 0
            for j in range(i, i + n):
                # 从加油站在圈中跑n圈,这里我用额外的空间组成环,可以用求余代替
                res += rem[j]
                if res<0:
                    # 如果缺油,提前跳出
                    break
            if res>=0:
                # 如果不是因缺油, 则表示完成跑完一圈的任务
                return i
        return -1

待续
在飞的小猪

你可能感兴趣的:(leetcode 11.12-11.18)