leecode

leecode128,最长连续子序列,哈希表枚举,要注意技巧,判断num-1是否在哈希表中,可以降低时间复杂度。

class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        nums_set = set(nums)
        long_path = 0
        for num in nums_set:
            if num-1 not in nums_set:
                current_num = num
                current_path = 1
                while current_num + 1 in nums_set:
                    current_num += 1
                    current_path += 1
                long_path = max(long_path,current_path)
        return long_path

旋转数组

leecode33,搜索旋转数组,二分后两边子数组一个有序一个无序,在有序的那一边继续搜索。但是要考虑重复数字的存在。

class Solution:
    def search(self, nums,target: int) -> int:
        if len(nums) == 0:
            return -1
        if len(nums) == 1:
            if nums[0] == target:
                return 0
            else:
                return -1
        l = 0
        r = len(nums)
        while l < r:
            mid = (l+r)//2
            if nums[mid] == target:
                return mid

            if nums[l] == nums[mid] and nums[r-1] == nums[mid]:
                l += 1
                r -= 1
            elif nums[l]<=nums[mid]:
                if nums[l]<=target<=nums[mid]:
                    r = mid
                else:
                    l = mid + 1
            else:
                if nums[mid]<=target<=nums[r-1]:
                    l = mid + 1
                else:
                    r = mid
        return -1

leecode81,旋转数组,leecode38加强版,有重复数字,难以判断子数组哪个有序,所以碰到nums[l],nums[mid],nums[r-1]三数字相等时,l和r分别加减1

class Solution:
    def search(self, nums,target: int) -> int:
        if len(nums) == 0:
            return -1
        if len(nums) == 1:
            return nums[0] == target
        l = 0
        r = len(nums)
        while l < r:
            mid = (l+r)//2
            if nums[mid] == target:
                return True

            if nums[l] == nums[mid] and nums[r-1] == nums[mid]:
                l += 1
                r -= 1
            elif nums[l]<=nums[mid]:
                if nums[l]<=target<=nums[mid]:
                    r = mid
                else:
                    l = mid + 1
            else:
                if nums[mid]<=target<=nums[r-1]:
                    l = mid + 1
                else:
                    r = mid
        return False

leecode153,查找旋转数组的最小值,二分法。注意起始区间l = 0,r = len(nums)-1,当nums[mid]>nums[r]时,说明mid在左边子区间,那么不考虑左边区间;当nums[mid]<nums[r]时,说明mid在右边区间,那么不考虑右边区间;当nums[mid] == nums[r]的时候,如果有重复元素,则无法区分,此时只能让r -= 1。返回的索引要考虑实际问题,本题就是最小元素的索引,即右边区间的最左边的点。

class Solution:
    def findMin(self, nums):    
        l,r = 0,len(nums)-1
        while l < r:
            mid = (l+r)//2
            if nums[mid]>nums[r]:
                l = mid + 1
            elif nums[mid] < nums[r]:
                r = mid
            else:
                r -= 1
            
        return nums[l]#或者nums[r]
    


if __name__ == "__main__":
    solution = Solution()
    nums = [3,4,5,1,2]
    ans = solution.findMin(nums)
    print(ans)

leecode154,寻找旋转数组的最小值,leecode153加强版本,包含重复元素,二分法。注意起始区间l = 0,r = len(nums)-1,当nums[mid]>nums[r]时,说明mid在左边子区间,那么不考虑左边区间;nums[mid]<nums[r]时,说明mid在右边区间,那么不考虑右边区间;当nums[mid] == nums[r]的时候,如果有重复元素,则无法区分,此时只能让r -= 1

class Solution:
    def findMin(self, nums):    
        l,r = 0,len(nums)
        while l < r:
            mid = (l+r)//2
            if nums[mid]>nums[r-1]:
                l = mid + 1
            elif nums[mid] < nums[r-1]:
                r = mid
            else:
                r -= 1
            
        return nums[l]#或者nums[r]

dfs

leecode695,岛屿的最大面积,dfs,要注意变量、边界条件和递归表达式三要素

class Solution:
    def dfs(self, grid, cur_i, cur_j) -> int:
        if cur_i < 0 or cur_j < 0 or cur_i>=len(grid) or cur_j>=len(grid[0]) or grid[cur_i][cur_j] != 1:
            return 0
        grid[cur_i][cur_j] = 0
        ans = 1
        for next_i,next_j in [0,1],[0,-1],[1,0],[-1,0]:
            di,dj = cur_i+next_i,cur_j+next_j
            ans += self.dfs(grid,di,dj)
        return ans



    def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
        ans = 0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                ans = max(ans,self.dfs(grid,i,j))
        return ans

leecode200,岛屿数量,dfs,具体代码思路和leecode695岛屿最大面积很相似

class Solution:
    def dfs(self, grid, cur_i, cur_j) -> int:
        if cur_i < 0 or cur_j < 0 or cur_i == len(grid) or cur_j == len(grid[0]) or grid[cur_i][cur_j] != "1":
            return
        
        grid[cur_i][cur_j] = "0"
        for di, dj in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
            next_i, next_j = cur_i + di, cur_j + dj
            self.dfs(grid, next_i, next_j)
    
    def numIslands(self, grid: List[List[str]]) -> int:
        ans = 0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j] == "1":
                    ans += 1
                    self.dfs(grid,i,j)
        return ans

leecode 463,岛屿的周长,遍历判断即可

class Solution:
    def islandPerimeter(self, grid: List[List[int]]) -> int:
        ans = 0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                tmp = 4
                if grid[i][j] == 1:
                    for next_i,next_j in [1,0],[-1,0],[0,1],[0,-1]:
                        di,dj = i + next_i,j+ next_j
                        if 0<=di<len(grid) and 0<=dj<len(grid[0]) and grid[di][dj] == 1:
                            tmp -= 1
                    ans += tmp
        return ans

反转链表

offer24、leecode206反转链表,双指针的迭代写法+递归写法,注意递归写法中值传递和结束过程。递归写法是不断递归修改节点的next,实质是从尾部节点开始修改。

# Definition for singly-linked list.
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None


class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if head == None:
            return head
        pre = None
        while head != None:
            tmp = head.next
            head.next = pre
            pre = head
            head = tmp
        return pre

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        def dfs(head,pre):
            if head == None:
                return pre
            res = dfs(head.next,head)
            head.next = pre
            return res

        pre = None   
        return dfs(head,pre)


def print_node(node):
    while node != None:
        print(node.val)
        node = node.next
if __name__ == "__main__":
    head = ListNode(1)
    head.next = ListNode(2)
    head.next.next = ListNode(3)
    solution = Solution()
    ans = solution.reverseList(head)
    print_node(ans)


    # [1,2,3,4,5]

leecode92,反转链表2,反转链表的加强版本,反转部分链表,要处理好left=1的边界条件

# Definition for singly-linked list.
class Solution:
    def reverseBetween(self, head, left: int, right: int):
        if head ==None or head.next ==None:
            return head
        i = 1
        pre = None
        start = head
        while i < left:
            pre = start
            start = start.next
            i += 1


        j = i
        cur_pre = None
        cur = start
        
        # 反转
        while j <= right:
            tmp = cur.next
            cur.next = cur_pre
            cur_pre = cur
            cur = tmp
            j += 1


        # 接起来,要考虑从链表开始就反转的情况,这个时候表头变了
        if pre !=None:
            pre.next = cur_pre
        start.next = cur


        if pre == None:
            head = cur_pre
        return head
    

打家劫舍

leecode198,打家劫舍,优化空间的动态规划

class Solution:
    def rob(self, nums):
        if len(nums) == 0:
            return 0
        if len(nums) == 1:
            return nums[0]
        dp_0 = nums[0]
        dp_1 = max(nums[0],nums[1])
        for i in range(2,len(nums)):
            tmp = dp_0
            dp_0 = dp_1
            dp_1 = max(nums[i]+tmp,dp_1)
        return dp_1

leecode213,打家劫舍,环形数组,对两个子数组进行动态规划,取结果最大的值

class Solution:
    def robrange(self,nums):
        dp_0 = nums[0]
        dp_1 = max(nums[0],nums[1])
        for i in range(2,len(nums)):
            tmp = dp_0
            dp_0 = dp_1
            dp_1 = max(nums[i]+tmp,dp_1)
        return dp_1


    def rob(self, nums):
        if len(nums) == 0:
            return 0
        if len(nums) == 1:
            return nums[0]
        if len(nums) == 2:
            return max(nums[0],nums[1])
        return max(self.robrange(nums[:len(nums)-1]),self.robrange(nums[1:]))

leecode337,打家劫舍,树形dp,注意模版

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def rob(self, root: Optional[TreeNode]) -> int:
        def dfs(root):
            if root == None:
                return 0,0
            l_rob,l_not_rob = dfs(root.left)
            r_rob,r_not_rob = dfs(root.right)
            rob = l_not_rob + r_not_rob + root.val
            not_rob = max(l_rob,l_not_rob) + max(r_rob,r_not_rob)
            return rob,not_rob
        return max(dfs(root))

最大化最小值/最小化最大值

leecode2569,打家劫舍,最小化最大值,二分法+dp

class Solution:
    def minCapability(self, nums: List[int], k: int) -> int:
        n = len(nums)
        if n == 1: return nums[0]
        left, right = 1, 1e9+1
        # 求最小最大值,所以将初始最大值设置为极大的正数,方便求最小最大值
        ans = right 

        while left < right:
            mid = (left + right) // 2   # 窃取能力mid
            # mid = (left + right) >> 1
            # dp[i],表示前 i 个(i从0算起)房间中可窃取金额不超过窃取能力mid的最大房间数
            dp = [0] * n
            # base case:第1个房屋dp[0],如果房屋金额<=窃取能力mid,选择窃取;
            # 第2个房屋dp[1],如果1、2间房屋其中一个满足条件,则可偷盗房间数为1,否则为0
            if nums[0] <= mid: dp[0] = 1
            dp[1] = 1 if min(nums[0], nums[1]) <= mid else 0


            for i in range(2, n):
                # 此房屋的金额nums[i]大于窃取能力mid,无法窃取,只能顺延dp[i-1]保证尽量大
                if nums[i] > mid:
                    dp[i] = dp[i - 1]
                    # 此房屋可以窃取, 可选择窃取(dp[i-2]+1)和不窃取(dp[i-1])的最优值
                else:
                    dp[i] = max(dp[i - 1], dp[i - 2] + 1)

                    # 只要窃取的房屋数量>=k即可成功,保存答案,继续寻找更小的符合条件的窃取能力
            if dp[n - 1] >= k:
                ans = mid
                right = mid
            else:
                left = mid + 1
        return int(right)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值