Python剑指offer打卡-16

本文探讨了多种数组相关的编程问题,包括最长递增子序列、两数之和、两数相加、三数之和及无重复字符的最长子串。针对这些问题,提供了动态规划和哈希表等高效解决方案,详细解析了算法思想和实现过程,帮助读者理解如何在实际编程中运用这些技术。
摘要由CSDN通过智能技术生成

Python剑指offer打卡-16

最长递增子序列

  • 问题描述

    问题描述:
        给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。子序列是
    由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。
    例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
    
    示例:
    输入:nums = [0,1,0,3,2,3]
    输出:4
    
    解题方法:
    动态规划
    dp[i]表示到当前结点i所表示的子序列的长度
    dp[i] = max(dp[i], dp[j - 1])
    
    时间复杂度:O(N^2)
    空间复杂度:O(N)  dp状态的存储
    
  • 代码

    class Solution:
    
        def lengthOfLIS(self, nums) -> int:
    
            if not nums: return 0
            # 转移结点
            dp = [1] * len(nums)
    
            # 状态转移
            for i in range(len(nums)):
                for j in range(i):
                    if nums[j] < nums[i]:
                        dp[i] = max(dp[i], dp[j] + 1)
    
            return max(dp)
    

两数之和

  • 问题描述

    问题描述:
    	给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 
    的那两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数
    组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案。
    
    解题方法:
    方法一:暴力求解
    时间复杂度O(N^2)
    空间复杂度O(1)
    
    方法二:哈希表(空间换时间)
    时间复杂度O(N)
    空间复杂度O(N)
    
    注意:
    同一个元素不能重复出现
    [4, 4, 2, 1, 2]   target = 4
    不能出现[2, 2] or [4, 4] 应该出现[2, 4]的索引组合,index从0开始
    
  • 代码

    class Solution:
        def twoSum(self, nums: List[int], target: int) -> List[int]:
    	"""暴力求解"""
        
            for i in range(len(nums)):
                for j in range(i + 1, len(nums)):
                    if nums[i] + nums[j] == target:
                        return [i, j]
            
            return []
        
        def twoSum(self, nums: List[int], target: int) -> List[int]:
        	"""哈希表"""    
            
            hashtable = dict()
            for i, num in enumerate(nums):
                if target - num in hashtable:
                    return [hashtable[target - num], i]
                # {values: index}
                hashtable[nums[i]] = i
            
            return []
    

两数相加

  • 问题描述

    问题描述:
        给你两个非空 的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,
    并且每个节点只能存储一位数字。请你将两个数相加,并以相同形式返回一个表示和的
    链表。你可以假设除了数字 0 之外,这两个数都不会以 0开头。
    
    解题方法:
    进位计算
    
    复杂度:
    时间复杂度:O(max(L1, L2))
    空间复杂度O(1)
    
    注意:
    每个节点只能存储一位数值
    
  • 代码

    图解

    在这里插入图片描述

    class ListNode:
    
        def __init__(self, val=0, next=None):
            self.val = val
            self.next = next
    
    
    class Solution:
    
        def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
    
            # 申请头结点
            dummy = cur = ListNode()
            # 进位节点
            carry = 0
            while l1 or l2:
    
                x = l1.val if l1 else 0
                y = l2.val if l2 else 0
                # 存储节点值
                sum = x + y + carry
                cur.next = ListNode(sum % 10)
                carry = sum // 10
                cur = cur.next
    
                # 更新节点
                if l1: l1 = l1.next
                if l2: l2 = l2.next
    
            if carry: cur.next = ListNode(carry)
    
            return dummy.next
    

三数之和

  • 问题描述

    问题描述:
    给你一个包含 n 个整数的数组nums,判断nums中是否存在三个元素 a,b,c ,使得a + b + c = 0 ?
    请你找出所有和为 0 且不重复的三元组。
    
    解题方法:
    (1)暴力求解
    时间复杂度:O(N^3)
    (2)二分法查找
    需要消除重复值:固定点消除,子区间内消除
    时间复杂度:O(N^2)
    
    注意:
    返回的list中不能含有重复的列表值
    如 [-1, 1, 0] [1, 0, -1]
    
  • 代码(解题思路

    图解

    说明在二分法中求和,需要注意在left 和 right 的移动中要消去重复出现的值,而在外层固定值i 的变换中要消去i领域内的重复值。

    在这里插入图片描述

    import numpy as np
    
    class Solution:
        
        def threeSum(self, nums: List[int]) -> List[List[int]]:
    
            res = []
            nums = sorted(nums)
            for i in range(len(nums)):
                for j in range(i + 1, len(nums)):
                    for k in range(j + 1, len(nums)):
                        if nums[i] + nums[j] + nums[k] == 0:
                            res.append([nums[i], nums[j], nums[k]])
            
            return np.unique(np.array(res), axis = 0).tolist()
        
        def threeSum(self, nums: List[int]) -> List[List[int]]:
    
            nums.sort()
            res = []
    
            for i in range(len(nums) - 2):
                # 三正数相加不能为零
                if nums[i] > 0: break
                if i > 0 and nums[i] == nums[i - 1]: continue
                # 固定当前值
                target = -nums[i]
                # 二分算法
                left, right = i + 1, len(nums) - 1
                while left < right:
                    if target == nums[left] + nums[right]:
                        res.append([nums[i], nums[left], nums[right]])
                        # 更新边界
                        left += 1
                        right -= 1
                        while left < right and nums[left] == nums[left - 1]:
                            left += 1
                        while left < right and nums[right] == nums[right + 1]:
                            right -= 1
                    elif target > nums[left] + nums[right]:
                        left += 1
                    else:
                        right -= 1
            return res
    
    

无重复字符的最长子串

  • 问题描述

    问题描述:
    给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
    
    解题方法:
    滑动窗口
    时间复杂度:O(n)
    
  • 代码(解题思路

    图解:窗口内无重复数值

    在这里插入图片描述

    class Solution:
        def lengthOfLongestSubstring(self, s: str) -> int:
    
            if not s: return 0
            # left 记录窗口左边界索引值
            left, max_len, cur_len = 0, 0, 0
            look_up = set()
    
            for i in range(len(s)):
                cur_len += 1
                # 循环判断,直到左边界唯一
                while s[i] in look_up:
                    look_up.remove(s[left])
                    left += 1
                    cur_len -= 1
                # 记录字符串最长长度
                if cur_len > max_len: max_len = cur_len
                look_up.add(s[i])
    
            return max_len
    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值