思路:这个题就其实比较新奇,是考察排序,但是排序的规则不是按照我们平时的数值大小。 针对此题,我们对字符串 x, y 的大小 作如下 自定义: 如果:x + y > y + x , 则 x > y; 如果:x + y == y + x , 则 x = y; 如果:x + y < y + x , 则 x < y; 按照我们自定义的规则进行排序即可,题目要求是最小的数,那么就按照降序排列。
classSolution: defsortColors(self, nums: List[int]) -> None: """ Do not return anything, modify nums in-place instead. """ '''荷兰国旗问题''' N = len(nums) L, R = -1, N i = L+1 while i < R: if L < R and nums[i] < 1: nums[i], nums[L+1] = nums[L+1], nums[i] L+=1 i+=1 elif L < R and nums[i] == 1: i+=1 else: nums[i], nums[R-1] = nums[R-1], nums[i] R -=1
思路1:这个题也可以理解为找寻找至少出现两次的元素,只不过多了一个条件,即两数索引之间的距离不能超过 k。 简单的思路是:用哈希表存储数字的索引,计算重复出现的数字的索引之差,满足条件则可以返回True; 否则就用最新的索引 i 进行覆盖,以方便下一次判断条件。
classSolution: defcontainsNearbyDuplicate(self, nums: List[int], k: int) -> bool: h = dict() N =len(nums) for i inrange(N): if nums[i] in h and i-h[nums[i]] <=k : # 如果哈希表中已经存在该数, 且索引之差 <=k returnTrue else: # 用最新的索引 i 覆盖 h[nums[i]] = i returnFalse
思路 2:还有一种方案,那就是 每次遍历到 i 时,将哈希表中,前 k 个位置 之前的元素 删除掉。如果是在最近的 k 个数范围内,就不删除。 即哈希表中只保留距离i最近的k个数,这样就不需要去计算是否符合索引值差小于等于k,因为只要没被删除的,就一定在 最近的 k 个范围。 该思路的时间消耗比思路1长,但是空间消耗比思路1小。
classSolution: defcontainsNearbyDuplicate(self, nums: List[int], k: int) -> bool: h = dict() N =len(nums) for i inrange(N): if i > k: # 说明目前遍历的已经超过了 k 个数 # 且仍未返回True # 那么直接删除 距离当前 i 超过 k 的元素对应的键值对 # 即哈希表中只保留距离i最近的k个数 h.pop(nums[i-(k+1)]) if nums[i] in h: # 哈希表中已存在该数, 说明是第二次出现了 returnTrue else: h[nums[i]] = i
classSolution: defcontainsNearbyAlmostDuplicate(self, nums: List[int], indexDiff: int, valueDiff: int) -> bool: h = dict() N =len(nums) t, k = valueDiff, indexDiff for i inrange(N): # 先计算当前数字的分桶序号 group_idx group_idx = nums[i] // (t + 1) if group_idx in h and i-h[group_idx] <=k : # 如果哈希表中已存在该序号,说明两数之差 <=t # 且索引之差也<=k returnTrue
# 要考虑左右相邻两个桶内是否也有符合条件的数 elif group_idx-1in h andabs(i-h[group_idx-1]) <= k andabs(nums[i]-nums[h[group_idx-1]]) <=t : # # 如果1.左桶存在; and 2.数字序号之差 <=k; and 3.数值之差<=t returnTrue elif group_idx+1in h andabs(i-h[group_idx+1]) <= k andabs(nums[i]-nums[h[group_idx+1]]) <=t : # # 如果1.右桶存在; and 2.数字序号之差 <=k; and 3.数值之差<=t returnTrue
classSolution: defmaximumGap(self, nums: List[int]) -> int: N = len(nums) if N < 2: return0 '''最基础的情况,元素都为非负整数''' max_v = max(nums) # d 这里在统计最高的位数 d = len(str(max_v))
for i inrange(d): radix = 10 ** i # radix 代表本次循环基于哪一个位 Groups = [[] for _ inrange(10)] # 初始化从0到9,共10个分组
for num in nums: digit = num // radix % 10 # 按照当前位的数字,将原始数据分别装入不同的group中 Groups[digit].append(num)
# 该 print 函数能打印各个阶段 数字装入分组后的状况, # 可以取消注释后打印中间结果,帮助理解 # print(i, Groups) j = 0 for group in Groups: for num in group: nums[j] = num j += 1 print(nums) max_res = 0 for m inrange(1,N): max_res = max(max_res, abs(nums[m-1]-nums[m])) # print(max_res) return max_res
for i inrange(d): radix = 10**i Groups = [ [] for _ inrange(10)] Groups_neg = [ [] for _ inrange(10)] # Groups_neg: [0:-9], [1:-8], [8:-1], [9:-0] for num in nums: digit = int(num/radix) % 10 if num > 0: Groups[digit].append(num) else: Groups_neg[digit-1].append(num)
j = 0 for group in Groups_neg: for num in group: nums[j] = num j+=1
for group in Groups: for num in group: nums[j] = num j+=1 return RadixSort(nums) # 因为我们是从小到大排序的,所以这里取数时要注意换算 return nums[len(nums) - k]
classSolution: deffindKthLargest(self, nums: List[int], k: int) -> int: defHeapify(a, index, heapsize): '''时间复杂度 o(logN) ''' L = 2*index+1 while L <= heapsize: R = L+1 large = R if(R<=heapsize and a[R] > a[L]) else L large = large if a[large] > a[index] else index if large == index : break a[index], a[large] = a[large], a[index] index = large L = 2*index+1 N = len(nums) '''构造大根堆 时间复杂度 o(N) ''' for i inrange(int(N/2), -1, -1): Heapify(nums, i, N-1) # small = min(nums)-1 small = -10001 # 用更小的数替换掉大根堆堆顶, 相当与将这个最大数给删除了,因为我们本来就不需要它 # k*O(logN) = O(logN) for _ inrange(k-1): nums[0] = small Heapify(nums, 0, N-1) return nums[0]
思路:该题是上一题的升级版,难度稍微上升了一点。因为这一次等于是要计算对应位置上的逆序对,而位置在排序的时候是会移动的,就是要在这里考虑这一点。 所以排序的时候,可以带着索引一起排;这样对每个位置计算其各个merge阶段的逆序对的时候,还是按照索引来进行改动。 将索引和数字绑定在一起形成一个元素:nums2 = [[idx, num] for idx, num in enumerate(nums)] 另外,由于我们是对每个位置计算其右侧的逆序对,所以这个题中,在考虑计算逆序对的时机时,应该是以left数为准,计算右侧有多少个数比它小。(上一题在merge时,是对右侧的每个数计算其左侧有多少个数可以和其组成逆序对,因为只考虑逆序对的个数,而不考虑具体哪个位置上逆序对的个数,所以这么写code方便一些)