977.有序数组的平方
学习视频地址:双指针法经典题目 | LeetCode:977.有序数组的平方_哔哩哔哩_bilibili
学习文档地址:代码随想录 (programmercarl.com)
学习开始时间:11:00-12:30
文档记录时间: 16:03- 17:00
状态:已听懂|可单独复写代码|需复习
1. 看到问题后的初始想法
总算有一道题看到代码后有头绪了,我的初始思路是先将目标数组所有元素平方,然后再对数组进行排序,结果一顿操作猛如虎,结果直接Out of time limit......后来我觉得是我排序算法的问题,我使用的是插入排序,时间复杂度是o(n2),因为我不了解快速排序(已经再b站找视频自学思想)所以暂时无法把我的最初想法实现落地(算法还是得好好学,我现在最基本的排序算法都只会冒泡、插入、选择。。。)但如果要我使用双指针来解题,那我直接卡住,什么双指针?怎么双指针?难道用快慢指针?我是谁,我在哪,我在做什么???
2. 看完随想录后的迭代想法
恍然大悟,双指针居然可以放在数组的头和尾!先来介绍一下双指针对于这道题目的思想与求法。首先我们需要知道977这道题的数组是升序排列的,也就是说是从负数往正数排列的,因此在数字平方后,总是数组的左右两头大,中间小(更加靠近0)。因此我们就在数组的头与尾部署2个指针,分别比较左右两个指针的大小,如果左边指针大,那就将左边指针的数据放入result数组中,然后左边指针向右移动一格;反之则将右边指针的数据放入result数组中,然后右边指针向左移动一格。多次迭代后,指针将依次逐渐移动向中间(数字平方后较小)。代码如下:
def sortedSquares(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
### 使用双指针法
first_node = 0
last_node = len(nums) - 1
k = len(nums) - 1
result = [0] * (k+1)
while first_node <= last_node:
if nums[first_node] ** 2 < nums[last_node] ** 2:
result[k] = nums[last_node] ** 2
last_node -= 1
else:
result[k] = nums[first_node] ** 2
first_node += 1
k -= 1
return result
再附加一个超时代码(下次学会快速排序的代码一定补上!)
def sortedSquares(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
for i, j in enumerate(nums):
nums[i] = j ** 2
for i in range(len(nums)-1):
preindex = i
current_num = nums[i + 1]
while preindex >= 0 and nums[preindex] > current_num:
nums[preindex+1] = nums[preindex]
preindex -= 1
nums[preindex+1] = current_num
return nums
Leetcode测试结果(第二个解法因为不是快速排序超时了。。。)
209.最小的子数组
学习视频地址:拿下滑动窗口! | LeetCode 209 长度最小的子数组_哔哩哔哩_bilibili
学习文档地址:代码随想录 (programmercarl.com)
学习开始时间:17:00-17:30
文档记录时间: 1:14- 1:28(朋友过生日陪朋友唱K打瓦去了哈哈哈哈)
状态:已听懂|可单独复写代码|需复习
1. 看到问题后的初始想法
第一次看到这个问题想到了暴力求解法,即移动滑动窗口的首部,并且循环滑动窗口尾部的位置,记录下符合条件时滑动窗口的长度,结果代码卡在了第18个例子,超时了哈哈哈哈哈哈。不过至少有进步,至少说明这个算法在牺牲一定时间的情况下是可行的。(然后因为赶着过朋友的生日聚会就果断放弃了继续钻研其他时间更短的方法)
2. 看完随想录后的迭代想法
真的是巧妙,仅仅是将遍历的对象由滑动窗口的首部移动到滑动窗口的尾部,就实现了时间复杂度的简化。算法的简单思路:迭代增加滑动窗口尾部的index,当滑动窗口的相加和大于或等于目标值时,记录当前滑动窗口的长短(取当前最小值作为result),然后将滑动窗口的起始位置往后移动一格(精髓!!!)并再次循环判断。将滑动窗口的起始位置向后移动一格与将滑动窗口的终末位置向后移动一格相比大大简化了运算,因为滑动窗口的终末位置就算移动到最后一位后,在下一次滑动窗口的起始位置向后移动一位后,仍然要回到起始位置(当前起始位置)进行遍历,而滑动窗口向后移动一位后就不需要再从第一个位置开始遍历了。
代码如下(每次看到这种优雅的代码都很爽)
def minSubArrayLen(self, target, nums):
"""
:type target: int
:type nums: List[int]
:rtype: int
"""
# 滑动窗口
i = 0
sums = 0
result = float('inf')
for j in range(len(nums)):
sums += nums[j]
while sums >= target:
length = j - i + 1
result = min(result, length)
sums -= nums[i]
i += 1
return 0 if result == float('inf') else result
leetcode测试结果
59.螺旋矩阵II
学习视频地址:一入循环深似海 | LeetCode:59.螺旋矩阵II_哔哩哔哩_bilibili
学习文档地址:代码随想录 (programmercarl.com)
学习开始时间:10:00 - 11:35
文档记录时间: 11:36 -
状态:已听懂|可单独复写代码|需复习
1. 看到问题后的初始想法
感觉需要用到for循环进行遍历,但是比较晕,因为我第一次看到问题时感觉需要多次判断边界条件,当初并没有想到不变量(处理时遵循左闭右开的原则)。。。
2. 看完随想录后的迭代想法
妙不可言,这道题大致的思想是把一圈一圈遍历正方形转化为离散的绕着正方形遍历——先绕着正方形最外圈遍历完,然后再开始绕着正方形第二层最外圈遍历,重复该步骤一直遍历到正方形最内层(如果是偶数层那就遍历完了,但如果是奇数层最后会留下一个正方形,我们单独拿出来补全即可)。一共需要填补n//2(n整除2)个正方形外圈。了解大致思路后,在实现上我们需要遵从左闭右开的原则,即在遍历单一的一条边时,我们填补这一条线的最左(上)端的格子一直到最右(下)端的格子,但不包括最右(下)端的格子。以上种方式遍历四条边后,你会发现最外圈的正方形也就遍历完了,接下来就是遍历里面的正方形了。
Talk is cheap, show me the code:
ef generateMatrix(self, n):
"""
:type n: int
:rtype: List[List[int]]
"""
# 左闭右开
matrix = [[0]*n for i in range(n)]
startx = 0
starty = 0
off = 1
count = 0
for round_count in range(n//2):
i = starty
j = startx
for j in range(startx, n-off):
count += 1
matrix[i][j] = count
j += 1
for i in range(starty, n-off):
count += 1
matrix[i][j] = count
i += 1
while j > startx:
count += 1
matrix[i][j] = count
j -= 1
while i > starty:
count += 1
matrix[i][j] = count
i -= 1
off += 1
startx += 1
starty += 1
if n % 2 == 1:
matrix[(n+1)/2-1][(n+1)/2-1] = n ** 2
return matrix
leetcode 结果