【日常系列】LeetCode《27·动态规划2》

news2024/9/22 20:27:32

数据规模->时间复杂度

<=10^4 😮(n^2)
<=10^7:o(nlogn)
<=10^8:o(n)
10^8<=:o(logn),o(1)

内容

1)爬楼梯、打家劫舍问题
2)0-1,多重,完全,二维被动背包问题

lc 70【剑指 10 - 2】【top100】: 爬楼梯
https://leetcode.cn/problems/climbing-stairs/
提示:
1 <= n <= 45
在这里插入图片描述

#方案一:dfs+记忆化
class Solution:
    def climbStairs(self, n: int) -> int:
        memo=[-1]*(n+1)
        def dfs(n):
            if n==1:return 1
            if n==2:return 2
            if memo[n]!=-1:return memo[n]
            #
            memo[n]=dfs(n-1)+dfs(n-2) #left+right
            return memo[n]
        return dfs(n)

#方案二:dp+压缩
class Solution:
    def climbStairs(self, n: int) -> int:
        dp=[-1]*(n+1) #走到i台阶,对应的方法数量
        dp1,dp2=1,2
        #[n-1]+1->[n],[n-2]+2->[n]
        #(注意([n-1]+1)已存在[n-2],所以[n-2]+1+1等价于[n-2]+2)
        for i in range(3,n+1):
            dp1=dp2
            dp2=dp1+dp2
        return dp2   

lc 746【剑指 088】:使用最小花费爬楼梯
https://leetcode.cn/problems/min-cost-climbing-stairs/
提示:
2 <= cost.length <= 1000
0 <= cost[i] <= 999
在这里插入图片描述

#方案一:回溯+dfs
class Solution:
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        n=len(cost)
        memo=[-1]*(n+1)
        def dfs(i):
            if i==0 or i==1:return 0 #从下标为 0 或下标为 1 的台阶开始爬楼梯,不需要体力值,只是从0->1或者0->2,需要cost[i]体力值
            if memo[i]!=-1:return memo[i]
            #
            memo[i]=min(dfs(i-1)+cost[i-1],dfs(i-2)+cost[i-2])#表示爬到i-1的最低花费+cost[i-1]->爬到i
            return memo[i]
        return dfs(n)
#方案二:dp+压缩
class Solution:
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        n=len(cost)
        prev=curr=0
        for i in range(2,n+1):
            tmp=curr   
            curr=min(curr+cost[i-1],prev+cost[i-2])
            prev=tmp       
        return curr       

lc 198【剑指 089】【top100】:打家劫舍
https://leetcode.cn/problems/house-robber/
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 400
在这里插入图片描述
在这里插入图片描述

#方案一:回溯+记忆化
#写法一
class Solution:
    def rob(self, nums: List[int]) -> int:
        n=len(nums)
        memo=[-1]*n # memo[i]:偷盗[i, nums.length - 1],包括i户(偷/不偷),区间房子得到的最大金额
        def dfs(i):
            if i>=n:return 0
            if memo[i]!=-1:return memo[i] 
            #
            memo[i]=max(dfs(i+1),dfs(i+2)+nums[i])
            return memo[i]
        return dfs(0)
#写法二
class Solution:
    def rob(self, nums: List[int]) -> int:
        n=len(nums)
        memo=[-1]*n
        def dfs(i):
            if i<0:return 0
            if memo[i]!=-1:return memo[i] #偷到i户,包括i户(偷/不偷),所能获得的最大金额
            #
            memo[i]=max(dfs(i-1),dfs(i-2)+nums[i])
            return memo[i]
        return dfs(n-1)

#方案二:dp+压缩
class Solution:
    def rob(self, nums: List[int]) -> int:
        n=len(nums)
        if n==1:return nums[0]
        
        dp=[-1]*n
        prev=curr=0
        
        for i in range(n):
            tmp=curr
            curr=max(prev+nums[i],curr)
            prev=tmp
        return curr

lc 213【剑指 090】:打家劫舍 II
https://leetcode.cn/problems/house-robber-ii/
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 1000
在这里插入图片描述

class Solution:
    def rob(self, nums: List[int]) -> int:
        n=len(nums)
        if n==1:return nums[0] 
        def rob1(i,j):  
            dp=[-1]*n
            #
            prev=curr=0
            for k in range(i,j+1):
                tmp=curr
                curr=max(prev+nums[k],curr)
                prev=tmp
            return curr
        return max(rob1(0,n-2),rob1(1,n-1)) #key:

lc 337【top100】:打家劫舍 III
https://leetcode.cn/problems/house-robber-iii/
提示:
树的节点数在 [1, 10^4] 范围内
0 <= Node.val <= 10^4
在这里插入图片描述

# 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(node):
            if not node:return [0,0]
            #
            left,right=dfs(node.left),dfs(node.right)
            #key:1)当不考虑当前节点,则在子节点中寻找到最优组合分(key-key-key)
            #2)当考虑当前节点时,则累加在不选子节点的情况下,获得的最优分
            res=[0]*2
            res[0]=max(left[0],left[1])+max(right[0],right[1])
            res[1]=left[0]+right[0]+node.val
            return res
        ans=dfs(root)
        return max(ans[0],ans[1])

0 - 1 背包问题:每种背包只能取一次
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#方案一:dfs-前序
def knapsack01(w, v, C):
    maxValue = float('-inf')
    def dfs(start,remain_w,curr_value):
        nonlocal maxValue
        maxValue=max(maxValue,curr_value) #处理当前节点
        #处理子节点
        for i in range(start,len(w)):
            child_i=i+1
            #剪枝
            if child_i==len(w):continue
            if remain_w-w[child_i]<0:continue
            dfs(child_i,remain_w-w[child_i],curr_value+v[child_i])
    dfs(-1, C, 0)
    return maxValue
print(knapsack01([3,4,5],[15,14,12],10))

#方案二:dfs-后序
def knapsack01(w, v, C):
    def dfs(start,remain_w):
        maxValue = 0 #key:位置,最底子节点maxValue从0开始
        #
        for i in range(start,len(w)):
            child_i=i+1
            if child_i==len(w):continue
            if remain_w-w[child_i]<0:continue
            #
            childmaxValue=dfs(child_i, remain_w - w[child_i])
            maxValue=max(maxValue,childmaxValue)  #考虑到,返回各子分支中的最大值

        k=0 if start==-1 else v[start]
        return maxValue+k

    return dfs(-1, C)
print(knapsack01([3,6,7],[15,10,11],10))

#方案三:dp
def knapsack01(w, v, c):
    dp=[[0]*(c+1) for _ in range(len(w))]

    for j in range(c+1):
        if j>=w[0]:dp[0][j]=v[0]

    for i in range(1,len(w)):
        for j in range(c+1):
            if j<w[i]:dp[i][j]=dp[i-1][j]
            else:dp[i][j]=max(dp[i-1][j],v[i]+dp[i-1][j-w[i]])
    return dp[len(w)-1][c]

print(knapsack01([3,6,7],[15,14,13],10))

#方案四:dp+状态压缩(注意状态转移方向)【重】

def knapsack01(w, v, c):
    dp=[0]*(c+1)

    #for j in range(c+1): #可以被下面统一化
        #if j>=w[0]:dp[j]=v[0] #dp[j]=max(0,v[i]+0)

    for i in range(len(w)):#1->0
        for j in range(w[i],-1,-1): #转移方向,使基于前面的状态没有被提前改变
            dp[j]=max(dp[j],v[i]+dp[j-w[i]])
    return dp[c]

print(knapsack01([3,6,7],[15,14,13],10))

完全背包问题:每种背包可以重复取
在这里插入图片描述

#dfs
def knapsackComplete(w, v, c):
    def dfs(start,remain_w):
        maxValue=0
        #处理子节点
        for i in range(start,len(w)):
            child_i=i
            #剪枝
            if child_i==-1 or child_i==len(w):continue
            if remain_w-w[child_i]<0:continue
            maxValue=max(maxValue,dfs(child_i,remain_w-w[child_i]))
        k=0 if start==-1 else v[start]
        return maxValue + k

    return dfs(-1, c)
print(knapsackComplete([3,6,7],[16,14,13],10))

#dp
def knapsackComplete(w, v, c):
    dp = [[0] * (c + 1) for _ in range(len(w))]

    for j in range(c + 1):
        dp[0][j] = (j//w[0])*v[0]

    for i in range(1, len(w)):
        for j in range(c + 1):
            max_cnt=j//w[i]
            for k in range(max_cnt+1):
                dp[i][j] = max(dp[i][j], k*v[i] + dp[i - 1][j - k*w[i]]) #key
    return dp[len(w) - 1][c]

print(knapsackComplete([3,3,7],[18,17,13],10))

#dp+时空优化【重】
def knapsackComplete(w, v, c):
    dp = [0] * (c + 1) #空间优化

    #for j in range(c + 1):
        #dp[j] = (j//w[0])*v[0]

    for i in range(len(w)):
        for j in range(w[i],c + 1):
        #放 第一个物品产生的价值永远大于等于放 第 2、3、4、5.... 个
        #如果放第一个物品产生的价值比不放这个物品产生的价值要小的话,那么不放物品,产生的价值最大
            dp[j]=max(dp[j],v[i]+dp[j-w[i]]) #时间优化 #key:#转移方向:使基于前面的状态被提前改变
            # max_cnt=j//w[i]
            # for k in range(max_cnt+1):
            #     dp[j] = max(dp[j], k*v[i] + dp[j - k*w[i]]) #key
    return dp[c]

print(knapsackComplete([3,3,7],[18,17,13],10))

#多重背包
def knapsackM(w, v, c, p):
    dp = [0] * (c + 1) #空间优化

    for i in range(len(w)):
        for j in range(c,w[i]-1,-1):#key:非重复选(<=p[i])
            max_cnt=min(j//w[i],p[i])
            for k in range(max_cnt+1):
                dp[j] = max(dp[j], k*v[i] + dp[j - k*w[i]]) #key
    return dp[c]

print(knapsackM([3,3,7],[18,17,13],10,[2,2,0]))


#二维背包
def knapsackComplete(w,g,W,G,v):#两种代价
    dp = [[0] * (G+1) for _ in range(W+1)] #空间优化

    for i in range(len(w)):
        for j in range(W,w[i]-1,-1):
            for k in range(G,g[i]-1,-1):
                dp[j][k] = max(dp[j][k], v[i] + dp[j-w[i]][k-g[i]]) #key

    return dp[w][G]

在这里插入图片描述

lc 322【剑指 103】:零钱兑换
https://leetcode.cn/problems/coin-change/
提示:
1 <= coins.length <= 12
1 <= coins[i] <= 2^31 - 1
0 <= amount <= 10^4
在这里插入图片描述

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp=[float('inf')]*(amount+1)
        
        dp[0]=0 #key-遗漏
        for i in range(len(coins)):
            for j in range(coins[i],amount+1):
                dp[j]=min(dp[j],1+dp[j-coins[i]])
        
        return dp[amount] if dp[amount]!=float('inf') else -1


lc 518 :零钱兑换 II
https://leetcode.cn/problems/coin-change-ii/
提示:
1 <= coins.length <= 300
1 <= coins[i] <= 5000
coins 中的所有值 互不相同
0 <= amount <= 5000
在这里插入图片描述

class Solution:
    def change(self, amount: int, coins: List[int]) -> int:
        dp=[0]*(amount+1)
        
        dp[0]=1 #key:例如dp[5]=dp[5]+dp[0],5凑5本身就是一种组合
        for i in range(len(coins)):
            for j in range(coins[i],amount+1):
                dp[j]=dp[j]+dp[j-coins[i]] #上一个状态中,本身的组合数+新coins[i]带来的新状态中,能得到的组合数
        
        return dp[amount]

lc 377【剑指 104】 :组合总和 Ⅳ
https://leetcode.cn/problems/combination-sum-iv/
提示:
1 <= nums.length <= 200
1 <= nums[i] <= 1000
nums 中的所有元素 互不相同
1 <= target <= 1000
进阶:
如果给定的数组中含有负数会发生什么?问题会产生何种变化?如果允许负数出现,需要向题目中添加哪些限制条件?
在这里插入图片描述

#请注意,顺序不同的序列被视作不同的组合。
class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        dp=[0]*(target+1)
        dp[0]=1
        for j in range(1,target+1): #key:for顺序
            for i in range(len(nums)):
                if j>=nums[i]:
                    dp[j]=dp[j]+dp[j-nums[i]]
        return dp[target]

lc 494【剑指 102】【top100】:目标和
https://leetcode.cn/problems/target-sum/
提示:
1 <= nums.length <= 20
0 <= nums[i] <= 1000
0 <= sum(nums[i]) <= 1000
-1000 <= target <= 1000

# 假设数组中所有数字的总和为 sum
# 假设前面设置为负数的数字的总和是 neg。那么设置为正数的数字的总和为 sum - neg
# 那么 (sum - neg) - neg = target => neg = (sum - target)/ 2
# 所以问题转为 0-1 背包问题:
# 在数组 nums 列表中不可重复的选择数字组合,使得组合中所有数字之和为 neg
# 求有多少组合数?
class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        diff=sum(nums)-target
        if diff%2==1 or diff<0:return 0 #key:sum(nums)>=0,target<=sum(nums)
        #
        neg=diff//2
        dp=[0]*(neg+1)
        dp[0]=1 #遗忘
        for i in range(len(nums)):
            for j in range(neg,nums[i]-1,-1):
                dp[j]=dp[j]+dp[j-nums[i]]
        return dp[neg]

lc 416 【剑指 101】【top100】:分割等和子集
https://leetcode.cn/problems/partition-equal-subset-sum/
提示:
1 <= nums.length <= 200
1 <= nums[i] <= 100
在这里插入图片描述

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        if sum(nums)%2==1:return False
        target=sum(nums)//2
        #
        dp=[False]*(target+1)
        dp[0]=True #遗忘
        for i in range(len(nums)):
            for j in range(target,nums[i]-1,-1):
                dp[j]=dp[j] or dp[j-nums[i]]
        
        return dp[target]

lc 279 :完全平方数【top100】
https://leetcode.cn/problems/perfect-squares/
提示:
1 <= n <= 10^4

# 完全平方数最小为 1,最大为 sqrt(n)
# 也就是我们要从 nums = [1, 2, ..., sqrt(n)] 数组里选出几个数,令其平方和为 target = n。
# 转化为是否可以用 nums 中的数(可重复选用)组合和成 n
class Solution:
    def numSquares(self, n: int) -> int:
        dp=[float('inf')]*(n+1)
        dp[0]=0
        for i in range(1,int(math.sqrt(n))+1):
            for j in range(i**2,n+1):
                dp[j]=min(dp[j],dp[j-i**2]+1)
        return dp[n]

lc 474 :一和零
https://leetcode.cn/problems/ones-and-zeroes/
提示:
1 <= strs.length <= 600
1 <= strs[i].length <= 100
strs[i] 仅由 ‘0’ 和 ‘1’ 组成
1 <= m, n <= 100

# 二维费用背包问题
# 物品是字符串数组中的字符串,选择每个字符串有两个代价,分别是 0 的个数和 1 的个数
# 两个代价都有最大值,0 的个数最多为 m,1 的个数最多为 n
# 求选择字符串得到的最大子集的大小
class Solution:
    def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
        dp=[[0]*(n+1) for _ in range(m+1)]

        for i in range(len(strs)):
            cnt=self.cntzeroone(strs[i])
            for j in range(m,cnt[0]-1,-1): #cnt[0]->w[j],cnt[1]->v[k]
                for k in range(n,cnt[1]-1,-1):
                    dp[j][k]=max(dp[j][k],dp[j-cnt[0]][k-cnt[1]]+1)
        
        return dp[m][n]
    
    def cntzeroone(self,s):
        cnt=[0]*2
        for i in range(len(s)):
            cnt[ord(s[i])-ord('0')]+=1
        return cnt

lc 139【top100】:单词拆分
https://leetcode.cn/problems/word-break/
注意:
不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
提示:
1 <= s.length <= 300
1 <= wordDict.length <= 1000
1 <= wordDict[i].length <= 20
s 和 wordDict[i] 仅有小写英文字母组成
wordDict 中的所有字符串 互不相同

# 在 wordDict 中可重复的选择字符串组合,看看是否存在可以组成字符串 s
# dp[i]: 表示前 i 个字符组成的子串是否可以被 wordDict 中的字符串组合而成
# 注意:这里的组合的顺序是任意的,所以先选择字符,再选择每个字典字符串
class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        dp=[False]*(len(s)+1)
        dp[0]=True
        for i in range(1,len(s)+1):
            for word in wordDict:
                if i>=len(word) and s[i-len(word):i]==word:#key:状态转移
                    dp[i]=dp[i] or dp[i-len(word)]
        return dp[len(s)]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/171762.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Maven仓库集成与使用

1.概念:Maven主要服务于基于java平台的项目构建(编译、测试、生成文档、打包、部署等)&#xff0c;依赖管理和项目信息管理。 2.四大特性: 2.1:依赖管理系统(jar包管理, jar 升级时修改配置文件即可) 依赖(Coordination):由groupId、artifactId、version组成 …

PHP MySQL 预处理语句

预处理语句对于防止 MySQL 注入是非常有用的。 预处理语句及绑定参数 预处理语句用于执行多个相同的 SQL 语句&#xff0c;并且执行效率更高。 预处理语句的工作原理如下&#xff1a; 预处理&#xff1a;创建 SQL 语句模板并发送到数据库。预留的值使用参数 "?" 标…

Python 实现 JSON 解析器

Json 解析 文章目录Json 解析Json 的组成对象结构数组结构词法分析逻辑性解析解析对象类型解析数组类型完整代码小结Json 的组成 JSON结构共有2种 对象结构数组结构 一个合法的JSON字符串可以包含这几种元素: 特殊符号,如"{" “}“表示一个JSON Object&#xff0…

将DataFrame进行转置的DataFrame.transpose()方法

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 将DataFrame进行转置 DataFrame.transpose() 选择题 关于以下python代码说法错误的一项是? import pandas as pd dfpd.DataFrame({a:[a1,a2],b:[b1,b2]}) print("【显示】df:\n"…

高德地图红绿灯读秒是怎么实现的?(一)

关于这个读秒实现功能众说风云&#xff0c;目前有两种说法&#xff0c;一种说是靠大数据分析&#xff0c;一种说是靠交管部门数据。 我们先看一下官方的回应&#xff1a;可以自行去抖音看官方号的解释。 以下为原答&#xff1a; 有人说是接入了地方交管数据&#xff0c;其实政策…

2022年度 FinClip 扩展 SDK 推荐!

2022年&#xff0c;FinClip 团队进行了24个产品迭代&#xff0c;为了丰富FinClip 的平台能力&#xff0c;除了核心SDK之外&#xff0c;我们还为开发者们提供了扩展SDK&#xff0c;扩展SDK是一个依赖核心SDK的库&#xff0c;里面提供了核心SDK中所没有的各种小程序API。 官方希…

arduino和物联网云端平台系列---物模型之事件

事件&#xff0c;先下个简单的定义就是发生了什么事件 系列文章都是已经完成了基本的库安装和使用为前提 物模型之事件 基本的添加步骤不描述了&#xff0c;设置一个测试用例 事件我已经设定好了&#xff0c;输出参数代表的是在云端得到的输出&#xff0c;需要我们在设备进行…

【程序环境和预处理】C语言

前言&#xff1a; 到此节便是我们C语言学习的终章了&#xff0c;对C语言的学习便告一段落了&#xff0c;到学完这一章节我们便要进入下一个主题的学习了。 目录1. 程序的翻译环境和执行环境2. 详解编译链接2.1 翻译环境2.2 编译本身也分为几个阶段2.3 运行环境3. 预处理详解3.1…

ESP32设备驱动-L3GD20三轴角速率传感器驱动

L3GD20三轴角速率传感器驱动 1、L3GD20介绍 L3GD20 是一款低功耗三轴角速率传感器。 它包括一个传感元件和一个 I2C 接口,能够通过数字接口 (I2C/SPI) 向外部世界提供测量的角速率。传感元件采用意法半导体开发的专用微加工工艺制造,用于在硅晶片上生产惯性传感器和执行器。…

高通Qualcomm处理器的手机或设备进EDL 9008模式的办法

适用于变砖的设备 由于我们有很多基于 Qualcomm 的设备&#xff0c;其中一些设备可能会古怪地猜测如何进入 EDL 模式&#xff0c;或者如何正确进入。 例如&#xff0c;对于 Alcatel&#xff0c;您必须先按住两个音量键&#xff0c;然后再按住其中一个&#xff0c;对于 CAT B35…

DocPrompt代码实现细节

数据预处理阶段 PaddleOCR PP-Structure&#xff1a;这个库其实是用于版面分析的一个开源库&#xff0c;参见&#xff1a;github: Layout-Parser/layout-parserhttps://github.com/Layout-Parser/layout-parser 代码推理阶段 Paddle-Inferencehttps://paddle-inference.readt…

[JavaEE]定时器

专栏简介: JavaEE从入门到进阶 题目来源: leetcode,牛客,剑指offer. 创作目标: 记录学习JavaEE学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录: 1.定时器的概念 2.标准库中的定时器 3.实现定时…

团灭LeetCode跳跃游戏(相关话题:贪心,BFS)

目录 LeetCode55跳跃游戏 LeetCode45. 跳跃游戏 II LeetCode1306. 跳跃游戏 III LeetCode1345. 跳跃游戏 IV LeetCode55跳跃游戏 给定一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否…

win32com操作word 第三集:Range精讲(一)

本课程《win32com操作word API精讲&项目实战》&#xff0c;本公众号以文字分享为主&#xff0c;B站与视频号则发布视频分享&#xff0c;ID均为&#xff1a;一灯编程 本集开始&#xff0c;将会深入Document接口。打开或创建一个文档都会产生一个Document对象&#xff0c;它代…

十大排序(Java版本)

排序分为比较排序和非比较排序两种&#xff0c;常见的排序为比较排序&#xff0c;共有七类&#xff1a;直接插入排序、希尔排序、选择排序、冒泡排序、堆排序、快速排序以及归并排序。另有三种非基于比较类的排序&#xff1a;计数排序、基数排序和桶排序。基于比较的排序直接插…

TreeMap和TreeSet的介绍

目录 1、认识 TreeMap 和 TreeSet 2、TreeMap 的主要成员变量 3、TreeMap 的主要构造方法 4、TreeMap 和 TreeSet 的元素必须可比较 5、TreeMap 和 TreeSet 关于 key 有序 6、TreeMap 和 TreeSet 的关系 7、总结 1、认识 TreeMap 和 TreeSet TreeMap 和 TreeSet 是Ja…

探索SpringMVC-组件之ViewResolver

前言 ViewResolver也就是视图解析器&#xff0c;他将是我们《探索SpringMVC》系列要介绍的最后一个常用的组件。其他组件&#xff1a;MultipartResolver、LocaleResolver、ThemeResolver、RequestToViewNameTranslator、FlashMapManager&#xff0c;相对简单&#xff0c;大家可…

一个想活得简单的程序猿的2022年终总结!

前言 今年的总结相比以往来说&#xff0c;可写的太少了&#xff0c;但看到我17年开始写的年终总结&#xff0c;已定下每年写下的承诺&#xff0c;因此即便可写的不多&#xff0c;但是还是写下吧&#xff0c;毕竟又过了一年&#xff0c;总有东西会留下&#xff01; 今年事件 疫…

【Linux杂篇】Windows远程登陆Linux、Linux静态IP配置

前言 如果要长期连接Linux环境&#xff0c;就需要给Linux配置一个静态IP&#xff0c;否则可能每次连接的IP都不一样而且还很麻烦。 除此之外&#xff0c;我们使用ssh远程登录的时候&#xff0c;每次都要输入密码&#xff0c;也很麻烦&#xff0c;所以建议配置ssh密钥&#xff…

执行 java -jar xxx.jar 的时候底层到底做了什么?

大家都知道我们常用的 SpringBoot 项目最终在线上运行的时候都是通过启动 java -jar xxx.jar 命令来运行的。那你有没有想过一个问题&#xff0c;那就是当我们执行 java -jar 命令后&#xff0c;到底底层做了什么就启动了我们的 SpringBoot 应用呢&#xff1f;或者说一个 Sprin…