【Leetcode】技巧系列
【Leetcode-6】
一、题目:Z字形变换
将一个给定字符串 s
根据给定的行数 numRows
,以从上往下、从左到右进行 Z 字形排列。
二、代码:
def convert(self, s: str, numRows: int) -> str: """ 设置n个list,一个个往里填,行到0或者n-1就转方向,空的位置不管 """ res = [''] * numRows direction = 1 # 代表向下,行+1 r = 0 # 当前处在第0行 for item in s: res[r] += item r = r+1 if direction > 0 else r-1 # 下一步要走的行 if r == numRows or r < 0: # 行超出边界 r = r-2 if r == numRows else r+2 # 退2步或进2步 direction = -direction # 换方向 res = ''.join(res) return res
【Leetcode-26】
一、题目:删除有序数组中的重复项
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
二、代码:
def removeDuplicates(self, nums: List[int]) -> int: """ 两个指针,一个指向处理完的位置,一个指向待处理的位置,若待处理的值和处理完的不相同则复制过来,处理完指针后移,返回处理完指针的位置 """ if len(nums) == 0: return 0 p = 0 for i, item in enumerate(nums): if item != nums[p]: p += 1 nums[p] = item return p+1 # 数组长度为指向位置+1
【Leetcode-27】
一、题目:移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
二、代码:
def removeElement(self, nums: List[int], val: int) -> int: p = -1 # 处理完的下标 for i in range(len(nums)): if val != nums[i]: p += 1 nums[p] = nums[i] return p+1
【Leetcode-54】
一、题目:螺旋矩阵
给你一个 m
行 n
列的矩阵 matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
二、代码:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]: """ 遍历过或者超出边界的为墙,撞墙则转方向,否则朝当前方向走,进来的地方为(0,-1) """ m, n = len(matrix), len(matrix[0]) directions = [[0, 1], [1, 0], [0, -1], [-1, 0]] dir_idx = 0 # 当前方向 x, y = 0, -1 # 当前所处位置 res = [] visited = set() for _ in range(m*n): # 所有数 direction = directions[dir_idx] new_x, new_y = x + direction[0], y + direction[1] if not (0<=new_x<m and 0<=new_y<n and (new_x, new_y) not in visited): # 撞墙或者已经遍历 dir_idx = (dir_idx+1) % len(directions) direction = directions[dir_idx] new_x, new_y = x + direction[0], y + direction[1] visited.add((new_x, new_y)) res.append(matrix[new_x][new_y]) x, y = new_x, new_y return res
【Leetcode-56】
一、题目:合并区间
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。
二、代码:
def merge(self, intervals: List[List[int]]) -> List[List[int]]: res = [] if len(intervals) == 0: return res intervals.sort(key=lambda x: x[0]) p = intervals[0] for item in intervals[1:]: if item[0] <= p[1]: p = [min(p[0], item[0]), max(p[1], item[1])] else: res.append(p) p = item res.append(p) return res
【Leetcode-88】
一、题目:合并两个有序数组
二、代码:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: """ 逆向双指针,避免额外空间,每次选最大的填入尾部 """ p = m + n - 1 # 最终结果指针 p1 = m - 1 p2 = n - 1 while p >= 0: val1 = nums1[p1] if p1 >= 0 else float('-inf') val2 = nums2[p2] if p2 >= 0 else float('-inf') if val1 > val2: nums1[p] = val1 p1 -= 1 else: nums1[p] = val2 p2 -= 1 p -= 1
【Leetcode-128】
一、题目:最长连续序列
二、代码:
def longestConsecutive(self, nums: List[int]) -> int: look_up = {} for item in nums: look_up[item] = 1 max_len = 0 for item in nums: if item-1 not in look_up: this_len = 1 while item + 1 in look_up: this_len += 1 item += 1 max_len = max(max_len, this_len) return max_len
【Leetcode-169】
一、题目:多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
二、代码:
ef majorityElement(self, nums: List[int]) -> int: major = nums[0] count = 1 for item in nums[1:]: if item == major: count += 1 else: count -= 1 if count == 0: major = item count = 1 return major
【Leetcode-238】
一、题目:除自身以外的乘积
给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。
二、代码:
def productExceptSelf(self, nums: List[int]) -> List[int]: n = len(nums) output = [1]*n # 计算每个位置左边的乘积 for i in range(1, n): output[i] = nums[i-1] * output[i-1] # 累乘右边的乘积 right_val = 1 for i in reversed(range(n)): output[i] = output[i] * right_val right_val = nums[i] * right_val return output
【Leetcode-280】
一、题目:摆动排序
给你一个无序的数组 nums
, 将该数字 原地 重排后使得 nums[0] <= nums[1] >= nums[2] <= nums[3]...
。答案不唯一。
二、代码:
def wiggleSort(self, nums: List[int]) -> None: """ 逐位与前一位比较,不对则对换,一次大一次小 """ n = len(nums) if n <= 1: return nums flag = 1 # 要求比前面的大,也可以等于 for i in range(1, n): if flag > 0: if nums[i] < nums[i-1]: nums[i], nums[i-1] = nums[i-1], nums[i] else: # 要求比前面的小,也可以等于 if nums[i] > nums[i-1]: nums[i], nums[i-1] = nums[i-1], nums[i] flag = -flag return nums
【Leetcode-283】
一、题目:移动零
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
二、代码:
def moveZeroes(self, nums: List[int]) -> None: """ Do not return anything, modify nums in-place instead. """ """ p指向已处理完序列的尾部,尾部向后扩展,遇到的字符不是0则调换到前面 """ p = 0 for i in range(len(nums)): # if i == 0: # continue if nums[i] != 0: nums[p], nums[i] = nums[i], nums[p] p += 1
【Leetcode-383】
一、题目:赎金信
给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串 ransom 能不能由第二个字符串 magazines 里面的字符构成。如果可以构成,返回 true ;否则返回 false。
(题目说明:为了不暴露赎金信字迹,要从杂志上搜索各个需要的字母,组成单词来表达意思。杂志字符串中的每个字符只能在赎金信字符串中使用一次。)
二、代码:
def canConstruct(self, ransomNote: str, magazine: str) -> bool: """ a中出现频率<b中出现频率 """ def get_cnt(s): res = dict() for item in s: cnt = res.get(item, 0) res[item] = cnt + 1 return res cnt1 = get_cnt(ransomNote) cnt2 = get_cnt(magazine) for k, n1 in cnt1.items(): n2 = cnt2.get(k, 0) if n1 > n2: return False return True
【Leetcode-406】
一、题目:根据身高重建队列
假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。
请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。
二、代码:
def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]: """ 先按身高排序,再插队 """ people.sort(key=lambda x: (-x[0], x[1])) res = [] # 已经排好队的人 for item in people: if len(res) > item[1]: res.insert(item[1], item) else: res.append(item) return res
【Leetcode-448】
一、题目:找到所有数组中消失的数字
二、代码:
def findDisappearedNumbers(self, nums: List[int]) -> List[int]: n = len(nums) res = [] for i in range(n): nums[i] -= 1 for item in nums: nums[item % n] += n for i, item in enumerate(nums): if item < n: res.append(i+1) return res
【Leetcode-581】
一、题目:最短无序连续子数组
给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
请你找出符合题意的 最短 子数组,并输出它的长度。
二、代码:
def findUnsortedSubarray(self, nums: List[int]) -> int: nums_new = sorted(nums) n = len(nums_new) start, end = -1, n for i in range(n): if nums[i] != nums_new[i]: end = i if nums[n-i-1] != nums_new[n-i-1]: start = n-i-1 if start == -1: return 0 else: return end-start+1
【Leetcode-621】
一、题目:任务调度器
二、代码:
def leastInterval(self, tasks: List[str], n: int) -> int: """ 最重复的任务的次数为k,设置k个桶,相同任务不能放入同一桶,即可满足要求,求桶里任务量(空闲也算任务),桶的大小为n+1,即每个桶执行完任务就填入冷却任务(此时也算执行其他任务)。但当冷却时间较小时,需要扩大桶的容量,导致每个桶都被填满,此时需要的时间为任务数。因此最终时间选择最大值。 """ from collections import Counter cnt = Counter(tasks) cnt_list = list(cnt.values()) k = max(cnt_list) # 前k-1个桶都装满,消耗的时间 t1 = (k-1)*(n+1) # 最后一个桶不一定装满,装的数为数量为k的任务个数 t2 = len([t for t in cnt_list if t==k]) return t1+t2 if t1+t2 > len(tasks) else len(tasks)