每日一题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. 数组的相对排序
给你两个数组,arr1
和 arr2
,
-
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. 距离顺序排列矩阵单元格
给出 R
行 C
列的矩阵,其中的单元格的整数坐标为 (r, c)
,满足 0 <= r < R
且 0 <= 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
待续
在飞的小猪