17.10. 主要元素
数组中占比超过一半的元素称之为主要元素。给定一个整数数组,找到它的主要元素。若没有,返回-1。
示例 1: 示例二: 示例 3:
输入:[1,2,5,9,5,9,5,5,5] 输入:[3,2] 输入:[2,2,1,1,1,2,2]
输出:5 输出:-1 输出:2
思路:主要元素个数大于数组长度的一半,一个主要元素与一个非主要元素相互抵消,最后剩下的就是主要元素
代码:
class Solution:
def majorityElement(self, nums: List[int]) -> int:
if not nums:
return
e,cnt = nums[0],1
#一个主要元素抵消一个非主要元素,最后剩下的一定是主要元素(存在主要元素)
for o in nums[1:]:
if cnt==0:
e,cnt = o,1
continue
if o!=e:
cnt -=1
else:
cnt +=1
#再遍历判断是否为主要元素
cnt =0
for num in nums:
if num == e:
cnt += 1
if cnt > (len(nums) // 2):
return e
else:
return -1
832. 翻转图像
给定一个二进制矩阵 A,我们想先水平翻转图像,然后反转图像并返回结果。
水平翻转图片就是将图片的每一行都进行翻转,即逆序。例如,水平翻转 [1, 1, 0] 的结果是 [0, 1, 1]。
反转图片的意思是图片中的 0 全部被 1 替换, 1 全部被 0 替换。例如,反转 [0, 1, 1] 的结果是 [1, 0, 0]。
示例 1:
输入: [[1,1,0],[1,0,1],[0,0,0]]
输出: [[1,0,0],[0,1,0],[1,1,1]]
解释: 首先翻转每一行: [[0,1,1],[1,0,1],[0,0,0]];
然后反转图片: [[1,0,0],[0,1,0],[1,1,1]]
示例2:
输入: [[1,1,0,0],[1,0,0,1],[0,1,1,1],[1,0,1,0]]
输出: [[1,1,0,0],[0,1,1,0],[0,0,0,1],[1,0,1,0]]
解释: 首先翻转每一行: [[0,0,1,1],[1,0,0,1],[1,1,1,0],[0,1,0,1]];
然后反转图片: [[1,1,0,0],[0,1,1,0],[0,0,0,1],[1,0,1,0]]
思路:交换对应位置,并且取反(与1取异或,0 ^ 1 = 1,1 ^ 1=0)
代码:
class Solution:
def flipAndInvertImage(self, A: List[List[int]]) -> List[List[int]]:
m = len(A);n=len(A[0])
mid = (n+1)//2
for i in range(m):
for j in range(mid):
A[i][j],A[i][n-j-1] = A[i][n-j-1] ^ 1,A[i][j] ^ 1
return A
1233. 删除子文件夹
你是一位系统管理员,手里有一份文件夹列表 folder,你的任务是要删除该列表中的所有 子文件夹,并以 任意顺序 返回剩下的文件夹。
我们这样定义「子文件夹」:
- 如果文件夹 folder[i] 位于另一个文件夹 folder[j] 下,那么 folder[i] 就是 folder[j] 的子文件夹。
文件夹的「路径」是由一个或多个按以下格式串联形成的字符串:
- / 后跟一个或者多个小写英文字母。
例如,/leetcode 和 /leetcode/problems 都是有效的路径,而空字符串和 / 不是。
示例1:
输入:folder = ["/a","/a/b","/c/d","/c/d/e","/c/f"]
输出:["/a","/c/d","/c/f"]
解释:"/a/b/" 是 "/a" 的子文件夹,而 "/c/d/e" 是 "/c/d" 的子文件夹。
示例2:
输入:folder = ["/a","/a/b/c","/a/b/d"]
输出:["/a"]
解释:文件夹 "/a/b/c" 和 "/a/b/d/" 都会被删除,因为它们都是 "/a" 的子文件夹。
示例3:
输入:folder = ["/a/b/c","/a/b/d","/a/b/ca"]
输出:["/a/b/c","/a/b/ca","/a/b/d"]
提示:
- 1 <= folder.length <= 4 * 10^4
- 2 <= folder[i].length <= 100
- folder[i] 只包含小写字母和 /
- folder[i] 总是以字符 / 起始
- 每个文件夹名都是唯一的
提示:用hash表存储所有的文件夹,遍历每一个文件夹的字符串前缀,如果前缀在hash表中,说明是子文件夹
class Solution:
def removeSubfolders(self, folder: List[str]) -> List[str]:
m= {}
for folde in folder:
m[folde]=1
res = []
for folde in folder:
tmp,j = "/",1
flag = True
fil_len = len(folde)
while j < fil_len: #取前缀,不能是整个字符串
if folde[j]=="/" and j!=1: #遍历到"/"字符时开始验证
if m.get(tmp,0)!=0: #前缀在hash表中,说明是子文件夹
flag = False
break
tmp +=folde[j]
j +=1
if flag: #将不是子文件夹的文件夹加入到最终结果中
res.append(folde)
return res
969. 煎饼排序
给定数组 A,我们可以对其进行煎饼翻转:我们选择一些正整数 k <= A.length,然后反转 A 的前 k 个元素的顺序。我们要执行零次或多次煎饼翻转(按顺序一次接一次地进行)以完成对数组 A 的排序。
返回能使 A 排序的煎饼翻转操作所对应的 k 值序列。任何将数组排序且翻转次数在 10 * A.length 范围内的有效答案都将被判断为正确。
示例1:
输入:[3,2,4,1]
输出:[4,2,4,3]
解释:
我们执行 4 次煎饼翻转,k 值分别为 4,2,4,和 3。
初始状态 A = [3, 2, 4, 1]
第一次翻转后 (k=4): A = [1, 4, 2, 3]
第二次翻转后 (k=2): A = [4, 1, 2, 3]
第三次翻转后 (k=4): A = [3, 2, 1, 4]
第四次翻转后 (k=3): A = [1, 2, 3, 4],此时已完成排序。
示例2:
输入:[1,2,3]
输出:[]
解释:
输入已经排序,因此不需要翻转任何内容。
请注意,其他可能的答案,如[3,3],也将被接受。
提示:
- 1 <= A.length <= 100
- A[i] 是 [1, 2, …, A.length] 的排列
思路1:将n个元素最大的元素先翻转到末尾,再翻转到末尾,再翻转前n-1个的元素的最大值到n-1个位置,一直到数组最前面
class Solution:
def pancakeSort(self, arr: List[int]) -> List[int]:
res = []
n = len(arr)
while n>1:
idx = arr.index(n) #[0,n)最大元素位置([0,n)最大元素一定为n)
if idx + 1 == n: #最大元素在末尾,不用翻转
n -= 1
continue
arr = arr[:idx+1][::-1] + arr[idx+1:] # 最大元素翻转到开头
res.append(idx+1) #记录翻转长度
res.append(n)
arr = arr[:n][::-1]+arr[n:] #最大元素翻转到结尾
n -= 1
return res
更快的思路2(两次翻转合并为一次)
代码
class Solution:
def pancakeSort(self, arr: List[int]) -> List[int]:
res = []
n = len(arr)
while n>1:
idx = arr.index(n)
if idx + 1 == n:
n -= 1
continue
res.append(idx+1)
res.append(n)
arr = arr[idx+1:n][::-1]+arr[:idx+1] + arr[n:] #一次翻转即可
n -= 1
return res
64. 最小路径和
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
思路:到点(i,j)的最短路径为= (到点(i-1,j)与到点(i,j-1)的路径的最小值) + 点(i,j)的值(动态规划的思路)
代码(直接修改原始矩阵,若不能,可以重新开辟一个一维数组):
class Solution:
def minPathSum(self, grid: List[List[int]]) -> int:
if not grid:
return 0
m = len(grid);n=len(grid[0])
for i in range(m):
for j in range(n):
if j>0 and i>0:
grid[i][j] += min(grid[i-1][j],grid[i][j-1]) #上,左最短路径的最小值
if i == 0 and j > 0:
grid[i][j] += grid[i][j-1] #第一行,直接取左边的点最短路径值
if i > 0 and j==0:
grid[i][j] += grid[i-1][j] #第二列,直接取上边的点最短路径值
return grid[m-1][n-1]
78. 子集
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
思路1:数组中的每一个元素都有两种情况,存在与不存在,采用递归的思路
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
re = [[]]
for num in nums:
re += [e + [num] for e in re]
return re
思路二:用二进制0,1来代表有无,从全0遍历到全1
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
re =[]
for i in range(2**n,2**(n+1)):
binnum = bin(i)[3:] #例:bin(5) : ‘0b101’ (type='str')
re.append([nums[j] for j in range(n) if binnum[j]=='1'])
return re
42. 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
思路:每个点能接到的雨点的数目之和为最终能够接到的雨水,每个点能接到的雨水为(左边的最高柱子,右边的最高柱子)之中的最小值减去此点的柱子高度
代码:
class Solution:
def trap(self, height: List[int]) -> int:
left_max,right_max = 0 , 0
i,j= 0,len(height)-1
ans = 0
while(i<j):
left_max = max(left_max,height[i])
right_max = max(right_max,height[j])
if(left_max<right_max):
ans += left_max-height[i]
i += 1
else:
ans += right_max-height[j]
j -= 1
return ans