刷题《面试经典150题》(第八天)

本文介绍了如何使用贪心算法解决买卖股票的最佳时机问题,以及涉及的其他技术点如链表操作(两数相加)、数组处理(跳跃游戏、旋转图像)、动态规划和区间合并。通过实例展示了如何在实际场景中应用这些算法解决问题。
摘要由CSDN通过智能技术生成

学习目标:


学习内容:

    1. 买卖股票的最佳时机 II→贪心/数组/动态规划
    1. 跳跃游戏
    1. 旋转图像
    1. 合并区间
    1. 简化路径
    1. 两数相加

学习时间:

4.12

知识点

学习内容:

122. 买卖股票的最佳时机 II

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。
示例 1:

输入:prices = [7,1,5,3,6,4] 输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 =
5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
总利润为 4 + 3 = 7 。
示例 2:
输入:prices = [1,2,3,4,5] 输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 => 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
总利润为 4 。
示例 3:

输入:prices = [7,6,4,3,1] 输出:0 解释:在这种情况下,
交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。

本题考虑贪心算法
我们想要的是摄取最高利益,也就是说,想法设法把股票在最低点买入,在最高点卖出。
在这里插入图片描述
根据图像进行理解,怎么判断是否当天要卖出股票呢?当然是从当天忘前一天看。如果当天股票大于前一天的股票,那么就选择在前一天买入,当天卖出(红色曲线部分);如果当年价格低于前一天的价格,则不进行操作。
这就是贪心算法,在每一步都选择利益最大的方式进行买卖。
代码如下

class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        n=len(prices)
        sum=0
        if n==1:
            return 0
        for i in range(1,n):
            if prices[i]-prices[i-1]>0:
                sum+=prices[i]-prices[i-1]
        return sum
if __name__ == "__main__":
    s = Solution()
    prices = [7,1,5,3,6,4]
    print(s.maxProfit(prices))

55. 跳跃游戏

给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。

示例 1:

输入:nums = [2,3,1,1,4] 输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3
步到达最后一个下标。
示例 2:

输入:nums = [3,2,1,0,4] 输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 ,
所以永远不可能到达最后一个下标。

思路:
每次都走最大的步数,也就是当前位置i+可走的最大步数nums[i]。如果碰到0,就进行回溯。

class Solution(object):
    def canJump(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        n=len(nums)
        if n==1:
            return True
        i=0
        while i!=n-1:
            i+=nums[i]
            if i>=n-1:
                return True
            else:
                if nums[i]==0:
                    j=1
                    while i-j>=0 and nums[i-j]+i-j<=i:
                        j+=1
                    if i-j==-1:
                        return False
                    else:
                        i=i-j
if __name__ == "__main__":
    s=Solution()
    nums = [3,2,1,0,4]
    print(s.canJump(nums))

48. 旋转图像

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

示例 1:

在这里插入图片描述

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 输出:[[7,4,1],[8,5,2],[9,6,3]]
示例 2:
在这里插入图片描述

输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]

矩阵先转置,再对称交换即可(即转置后,第一列和最后一列交换,第二列和倒数第二列交换。。。。。。)

import numpy as np
class Solution(object):
    def rotate(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: None Do not return anything, modify matrix in-place instead.
        """
        n = len(matrix[0])
        for i in range(n):
            for j in range(i,n):
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
        i=0
        j=n-1
        while i<j:
            for k in range(n):
                matrix[k][i],matrix[k][j]=matrix[k][j],matrix[k][i]
            i+=1
            j-=1

if __name__ == "__main__":
    s=Solution()
    matrix = [[1,2,3],
              [4,5,6],
              [7,8,9]]
    print(s.rotate(matrix))

56. 合并区间

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

示例 1:

输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:

输入:intervals = [[1,4],[4,5]] 输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。

先让数组按照第一列排序,这样就不用考虑合并区间的左侧的情况了。
建立ans用来保存区间
若ans为空,那么直接把区间加入ans
否则进行判断,是否最后加入ans数组区间的右侧大于当前遍历区间的左侧,若大于,则说明区间重合,需要进行合并操作。
绘制了散点图方便理解一些

在这里插入图片描述

class Solution(object):
    def merge(self, intervals):
        """
        :type intervals: List[List[int]]
        :rtype: List[List[int]]
        """
        ans=[]
        n=len(intervals)
        intervals=sorted(intervals,key=lambda x:x[0])
        i=0
        while i < n:
            if len(ans)==0:
                ans.append([intervals[i][0],intervals[i][1]])
            else:
                if ans[-1][1]>=intervals[i][0]:
                    ans[-1][1]=max(ans[-1][1],intervals[i][1])
                else:
                    ans.append([intervals[i][0],intervals[i][1]])
            i+=1
        return ans

if __name__ == "__main__":
    s=Solution()
    intervals = [[1,3],[2,6],[8,10],[15,18]]
    print(s.merge(intervals))

71. 简化路径

给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 ‘/’ 开头),请你将其转化为更加简洁的规范路径。

在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…)
表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。任意多个连续的斜杠(即,‘//’)都被视为单个斜杠 ‘/’ 。
对于此问题,任何其他格式的点(例如,‘…’)均被视为文件/目录名称。

请注意,返回的 规范路径 必须遵循下述格式:

始终以斜杠 ‘/’ 开头。 两个目录名之间必须只有一个斜杠 ‘/’ 。 最后一个目录名(如果存在)不能 以 ‘/’ 结尾。
此外,路径仅包含从根目录到目标文件或目录的路径上的目录(即,不含 ‘.’ 或 ‘…’)。 返回简化后得到的 规范路径 。

示例 1:

输入:path = “/home/” 输出:“/home” 解释:注意,最后一个目录名后面没有斜杠。
示例 2:

输入:path = “/…/” 输出:“/” 解释:从根目录向上一级是不可行的,因为根目录是你可以到达的最高级。
示例 3:

输入:path = “/home//foo/” 输出:“/home/foo” 解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。 示例
4:

输入:path = “/a/./b/…/…/c/” 输出:“/c”

有一说一,这破题目够长的,但是题倒是不难熬

代码:

class Solution(object):
    def simplifyPath(self, path):
        """
        :type path: str
        :rtype: str
        """
        str1=[]
        path=path.split('/')
        path=[x for x in path if x!='' and x!='.'] #去除''元素
        for i in path:
            str1.append(i)
            if i=='..':
                str1.pop()
                if len(str1)!=0:
                    str1.pop()
        str1='/'+'/'.join(str1)
        return str1
if __name__ == "__main__":
    s=Solution()
    path = "/a/./b/../../c/"
    print(s.simplifyPath(path))

2. 两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:
在这里插入图片描述

输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8] 解释:342 + 465 = 807.
示例 2:

输入:l1 = [0], l2 = [0] 输出:[0] 示例 3:

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] 输出:[8,9,9,9,0,0,0,1]

简单题,考虑好进位就好啦!

# 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 addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        carry = 0
        l_h=ListNode()
        node=l_h
        while l1 and l2:
            node.next=ListNode(l1.val+l2.val+carry)
            node=node.next
            carry=0
            if node.val>9:
                carry=1
                node.val=node.val%10
            l1=l1.next
            l2=l2.next
        if l1:
            while l1:
                node.next=ListNode(l1.val+carry)
                carry=0
                node=node.next
                if node.val>9:
                    carry=1
                    node.val=node.val%10
                l1=l1.next
        if l2:
            while l2:
                node.next=ListNode(l2.val+carry)
                carry=0
                node=node.next
                if node.val>9:
                    carry=1
                    node.val=node.val%10
                l2=l2.next
        if carry==1:
            node.next=ListNode(carry)
        return l_h.next
if __name__ == "__main__":
    s=Solution()
    l1=ListNode(2)
    l1.next = ListNode(4)
    l1.next.next = ListNode(9)
    l2=ListNode(5)
    l2.next = ListNode(6)
    l2.next.next = ListNode(4)
    l2.next.next.next = ListNode(9)
    # print(s.addTwoNumbers(l1,l2))
    node=s.addTwoNumbers(l1,l2)
    while node:
        print(node.val)
        node = node.next

最后成果

- 122. 买卖股票的最佳时机 II
- 55. 跳跃游戏
- 48. 旋转图像
- 56. 合并区间
- 71. 简化路径
- 2. 两数相加

结论

道友,加油!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值