Day13
reverseKGroup(K个一组反转链表)
方法一:
头插法实现原地逆置,每次截取指定长度的链表传入
# Definition for singly-linked list.
class ListNode(object):
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution(object):
def reverseKGroup(self, head, k):
length=0
headNode=ListNode(-1)
headNode.next=head
work=headNode
while work.next is not None:
length+=1
work=work.next
work=headNode
for _ in range(length//k):
start = work.next
end = start
for _ in range(k - 1):
end = end.next
next_group = end.next
end.next = None
# 反转当前组
reversed_start = self.reverseall(start)
# 将反转后的组连接到前一组
work.next = reversed_start
# 将反转后的组的最后一个节点连接到下一组的起始节点
start.next = next_group
# 更新work为当前组的最后一个节点
work= start
return headNode.next
def reverseall(self,head):
headNode=ListNode(-1)
headNode.next=str
work=headNode.next
#头插法实现链表反转
while work is not None:
nextnode=work.next
work.next=headNode.next
headNode.next=work
work=nextnode
return headNode.next
removeDuplicates(删除有序数组重复项)
方法一:双指针
class Solution(object):
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if not nums:
return 0
# 双指针法
write_ptr = 0
for read_ptr in range(1, len(nums)):
if nums[read_ptr] != nums[write_ptr]:
write_ptr += 1
nums[write_ptr] = nums[read_ptr]
return write_ptr + 1
方法二:想采取一个数组,记录每个元素出现的次数,但是负数没法处理,而且若最大值较大,非常浪费时间同时还浪费空间,所以不要用
removeElement(移除元素)
过分简单了
if not nums:
return 0
writeIndex=0
for readIndex in range(len(nums)):
if(nums[readIndex])!=val:
nums[writeIndex]=nums[readIndex]
writeIndex+=1
return writeIndex
strStr(找第一个匹配)
方法一:朴素匹配
hayIndex=0
while hayIndex<len(haystack):
sameIndex = hayIndex
if hayIndex+len(needle)>len(haystack):
return -1
for needIndex in range(len(needle)):
if haystack[hayIndex]==needle[needIndex]:
hayIndex+=1
else:
hayIndex=sameIndex+1
sameIndex=-1
break
if sameIndex!=-1:
return sameIndex
return -1
方法二:KMP算法(难)
next数组的生成方法是最值得学习记忆的,next数组的含义为模式串在该位置失配时,模式串指针应该当重新回溯到的位置。在第一遍遍历时,就把模式串即当模式串,又当匹配串,i指针不用回溯,j指针指向其前驱,初始时,next数组都为-1,之所以都为-1,是为了不用给第一个节点赋值时特殊处理。当为-1,说明前面没有一个元素和字符串前面元素相同,在赋值过程中,如果i和j对应值相同,说明不用回溯,i前的j个元素和字符串前j个元素是相同的,可以直接为i+1赋值为j+1。不相同的话需要回溯。
class Solution(object):
def strStr(self, haystack, needle):
"""
:type haystack: str
:type needle: str
:rtype: int
"""
if not needle:
return 0
#求next数组
nextList=[-1]*len(needle)
i=0
j=-1
while(i<len(needle)-1):
if j==-1 or needle[i]==needle[j]:
i+=1
j+=1
nextList[i]=j
else:
j=nextList[j]
len_hay = len(haystack)
len_needle = len(needle)
i = j = 0 # i遍历haystack,j遍历needle
while i < len_hay and j < len_needle:
# 当j=-1(初始状态)或字符匹配时
if j == -1 or haystack[i] == needle[j]:
i += 1
j += 1
else:
# 利用next数组跳转
j = nextList[j]
# 匹配成功返回起始位置
return i - j if j == len_needle else -1
Title30
findSubstring(串联所有单词的子串)难题
首先,由于word.length最大可达5000,所以,不太可能实现全部单词拼接后,利用KMP回去找位置,这样时间复杂度过高
所以采取的是逆向的思路,把字符串拆成单词去查找字典当中是否存在
在解题前:
首先,需要知道的是,判断字典是否相同时,只需要判断所有键是否相同,且键值对是否相同,字典没有顺序的区别,所以,更加适合去判断在本题当中。
窗口是滚动式的向前移动而不是平移,即前面单词滚出去,后面单词滚进来,形成一个新的组合
根据起点不同,拆出来的单词组合会不一样
class Solution(object):
def findSubstring(self, s, words):
"""
:type s: str
:type words: List[str]
:rtype: List[int]
"""
if not words:
return []
word_len = len(words[0])
total_words = len(words)
window_len = word_len * total_words
s_len = len(s)
result = []
# 构建目标字典
#把words转为字典的样子,因为有可能出现相同的字母,所以用字典去判断更为方便
target = {}
for word in words:
target[word] = target.get(word, 0) + 1
# 遍历所有起始偏移量 (0~word_len-1)
for offset in range(word_len):
#剩余长度不足时,即当前字符串太短,不能够填满滑动窗口时,结束本轮循环
if offset + window_len > s_len:
continue
# 使用 start 表示窗口的起始位置,并且始终指向起始位置
start = offset # 初始化窗口起点为当前偏移量
#统计窗口内部的单词划分情况,current用于记录窗口内的单词情况
current = {}
# 初始化窗口内的单词统计
for j in range(start, start + window_len, word_len):
word = s[j:j + word_len]
#这种写法等价于上面的if-else,有的时候给值,没的话给0
current[word] = current.get(word, 0) + 1
# 检查初始窗口是否匹配
if current == target:
result.append(start)
# 滑动窗口
while start + window_len + word_len <= s_len:
# 移出左侧单词
left_word = s[start:start + word_len]
# 安全处理:使用 get 方法避免 KeyError
if current.get(left_word, 0) == 1:
del current[left_word]
else:
current[left_word] -= 1
# 窗口右移一个单词长度
start += word_len
# 移入右侧新单词(正确的索引计算)
right_word_start = start + window_len - word_len
right_word = s[right_word_start:right_word_start + word_len]
current[right_word] = current.get(right_word, 0) + 1
# 检查是否匹配
if current == target:
result.append(start)
return result
Day14
searchRange(找第一个位置和最后一个位置)简单
class Solution(object):
def searchRange(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
if not nums:
return [-1,-1]
position=-1
left=0
right=len(nums)-1
while left<=right:
mid=(left+right)//2
if nums[mid]==target:
position=mid
break
elif nums[mid]<target:
left=mid+1
else:
right=mid-1
if position==-1:
return [-1,-1]
else:
left,right=position,position
while left>0:
if nums[left-1]==target:
left-=1
else:
break
while right<len(nums)-1:
if nums[right+1]==target:
right+=1
else:
break
return [left,right]