LeetCode
无他, 唯手熟尔
Section 01
#167 两数之和等于目标值(双指针)
# #167 两数之和等于目标值(双指针), 思路:
# 1.使用两个整数变量跟踪这个数组的左右两端(即索引);
# 2.在while循环内(当索引l<r时), 进行全判断: 当前两数和大于/小于/等于目标数;
# 3.上述判断为等于的情况时, 返回左右索引各+1的结果(因要求: 不从0开始);
def twoSum(self, numbers, target):
""" :type numbers: List[int]
:type target: int
:rtype: List[int] """
numCount = len(numbers)
l = 0
r = numCount - 1
# 开始进入寻数代码;
while l < r:
# 关键逻辑: 因numbers已经是有序数组, 故大于target时要减小和, 只能将右索引左移, 反之亦然;
if numbers[l] + numbers[r] > target:
r -= 1
elif numbers[l] + numbers[r] < target:
l += 1
else:
return [l+1, r+1] # Trick: 索引不从0开始;
#215 快速选择/堆排序(排序)
# 题目: 在未排序的数组中找到第k个最大的元素.
# 请注意, 你需要找的是数组排序后的第k个最大的元素, 而不是第k个不同的元素.
# 思路:
# 1.随机选取一个pivotIndex, 并对其对应的pivotValue进行排序, 看能排到第几大;
# 2.如果这个随机值不是第k大的话, 则修改l或r边界, 重新partition;
# 3.注意: 经过partition后的nums是'半排序'的(与cursorIndex所在位置值大小的比较是知道的(左侧大, 右侧小),
# 不知道的是左侧或右侧区间内每个元素间的大小顺序;
# 另(复杂): 这个算法太过复杂(Unix原则: 简单事情不复杂说, 复杂任务分块成简单子任务): 要重写;
# 另(复杂+1): 把上面的'思路3'写完, 越发觉得这个算法太繁杂了('太过精巧'(每轮partition(), cursorIndex = l,
# 即: cursorIndex的值在l值的基础上累加, 差点没看出来), 不适宜思考);
class Solution(object):
def findKthLargest(self, nums, k):
""" :type nums: List[int]
:type k: int
:rtype: int """
# Index: 左端, 右端, 第k大的索引(为'k-1');
l, r, k = 0, len(nums)-1, k-1
# 进入循环, 不断地分裂(partition)直到return;
while 1:
# 返回: cursorIndex => 它左侧的值比它这个位置的值大, 第cursorIndex大的值的索引;
p = self.partition(nums, l, r)
if p == k:
return nums[p]
elif p > k:
# 若没'命中', 则新的右界取到p的左侧, 继续调用partition()方法, 此更新临界index的操作, 是partition;
# 注: 经过一轮partition后, 在nums中, cursorIndex(即p)左侧(含它本身)的值都比pivotValue大;
r = p - 1
else:
# 同上, '右侧'的值都比pivotValue小;
l = p + 1
# 因为pivotValue是随机选中的, 故不会一次命中到列表中的第k大的值;
# 修改完index值后, 继续partition, 直到随机取得的pivotIndex刚好是第k大的值的index(return nums[p]);
# 逻辑: 语言是苍白的, 看图会比较好, 但图也不是万能的: 牵扯到时序问题, 人看图也要晕;
# 注意传进来的参数: 一个list, 两个index; 返回一个index: ;
def partition(self, nums, l, r):
pivotIndex = random.randint(l,r) # 在l值和r值之间的随机值(index), 包含l和r;
pivotValue = nums[pivotIndex] # pivotValue是在数组的index l和r之间的随机值;
# 互换值, 程序trick, 下面for从l+1开始比较, 这么做就让pivotValue不参与比较而nums[l]要参与比较;
nums[l],nums[pivotIndex] = nums[pivotIndex],nums[l]
cursorIndex = l # cursorIndex是"会更新"的索引, 从l开始;
# 将大于pivotValue的值都调换到左边: 从l+1到r(包含)为止;
for i in range(l+1, r+1):
if nums[i] > pivotValue: # i的初值大于l, 此if语句用于partition;
cursorIndex += 1 # cursorIndex的初值是l;
# print(i, " ", cursorIndex)
# 当前满足'>pivotValue'条件的nums[i]与'+1'后的cursorIndex位置的值互换: 大的值换到左边去, 小的到右边;
nums[i],nums[cursorIndex] = nums[cursorIndex],nums[i]
# 关键一行: 此时的nums[l]是原pivotValue, 在上述for(l+1,r+1(不含))进行大值筛选之后,
# 原nums[l]也已经与pivotValue比较过了, 而此时是要将pivotValue(nums[l])与cursorIndex位置的值交换;
nums[l],nums[cursorIndex] = nums[cursorIndex],nums[l]
return cursorIndex # 返回pivotValue位置的索引值, 代表了第cursorIndex大的值;
#347 桶排序(排序)
#075 荷兰国旗问题[Ref]
题目描述: 给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。此题中,我们使用整数 0, 1 和 2 分别表示红色、白色和蓝色。
def sortColors(self, nums):
''' 荷兰三色旗问题解 '''
# 索引的定义: curr是当前考虑元素的下标
# 对于所有 idx < p0 : nums[idx] = 0
# 对于所有 idx > p2 : nums[idx] = 2
p0 = curr = 0 # p0指向类别0, 及游标index;
p2 = len(nums) - 1 # p2指向类别2;
while curr <= p2:
# 每次while循环, 分三种情况处理;
if nums[curr] == 0:
# curr所指为0, 需将curr位置的值调换到p0区域;
nums[p0],nums[curr] = nums[curr],nums[p0]
p0 += 1
curr += 1
elif nums[curr] == 2:
# 同上一情况: 将2值调到列表尾部, 并操作更新index, 此处不更新curr, 细微差别, 能否有限状态机一下;
nums[curr],nums[p2] = nums[p2],nums[curr]
p2 -= 1
else:
# 类别为1, 则不调换值, 且curr与p0这两个索引拉开了值/距离;
curr += 1
#455 贪心: