leetcode刷题记录

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]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值