目录
70.爬楼梯
题意:
假设你正在爬楼梯。需要
n
阶你才能到达楼顶。每次你可以爬
1
或2
个台阶。你有多少种不同的方法可以爬到楼顶呢?提示:
1 <= n <= 45
【输入样例】n=2【输出样例】2
解题思路:
- 明确当爬到第一阶台阶的时候,只有一种做法,就是这一步爬1个台阶;爬到第二阶台阶的时候有两种做法,就是走2个1台阶或1次2台阶。
2.当你要爬到第n阶台阶的时候,你有两种选择,一种选择是最后一步走1个台阶,意味着你的爬法=走到n-1个台阶的爬法;第二种选择是最后一步走2个台阶,意味着你的爬法=走到n-2个台阶的爬法;所有走到n阶的爬法应该是走到n-1+走到n-2
- 因为n的范围很小,用数组实现,如果要方便直接将num[1]和num[2]的值先赋值好的话,初始化不要写new int[n],不然需要先判断n是否大于1,是否大于2.
java
class Solution {
public int climbStairs(int n) {
int[] num=new int[50];
num[1]=1;
num[2]=2;
for(int i=3;i<=n;i++){
num[i] = num[i-1]+num[i-2];
}
return num[n];
}
}
时间: 击败了100.00%
内存: 击败了39.14%
198.打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你不触动警报装置的情况下,一夜之内能够偷窃到的最高金额。
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 400
【输入样例】[1,2,3,1]【输出样例】4
解题思路:1.定义一个数组count存储打劫到第i家的时候可以获得的最高金额;
2.寻找关系,为了不触动警报的前提下获取最多金额,我们采取隔房打劫的思路,在第i家的时候,如果选择打劫第i家,那么其金额应该是nums[i]+count[i-2];如果不选择打劫第i家,到这里的的金额是count[i-1],要获得最高的金额,就需要比较哪一种做法金额较高;
- 确定初始值,打劫第一家的时候,没有选择,count[1]=nums[1],打劫第二家也一样,不能触发警报,只能打劫本身count[2]=nums[2],但是,其也可以选择不打劫第二家,打劫第一家,即count[2]=max(nums[2],count[1])
java
class Solution {
public int rob(int[] nums) {
int len = nums.length;
int[] count = new int[len];
count[0] = nums[0];
if(len >= 2 )
count[1] = Math.max(nums[1],count[0]);
for(int i = 2;i<len;++i){
count[i] = Math.max(count[i-1],count[i-2]+nums[i]);
}
return count[len-1];
}
}
时间: 击败了100.00%
内存: 击败了67.42%
139.单词拆分
给你一个字符串
s
和一个字符串列表wordDict
作为字典。请你判断是否可以利用字典中出现的单词拼接出s
。**注意:**不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
提示:
1 <= s.length <= 300
1 <= wordDict.length <= 1000
1 <= wordDict[i].length <= 20
s
和wordDict[i]
仅由小写英文字母组成wordDict
中的所有字符串 互不相同
【输入样例】s = "leetcode", wordDict = ["leet", "code"]【输出样例】true
解题思路:
定义数组dp[i],表示字符串长度为i时,是否可以拆解为一个或多个在字典中出现的单词,可以为true,不让为false;
dp[0]表示空字符串,此时默认为true
字符串长度为i时,dp[i]的取值依靠什么?假设j<i,dp[j]=true且字符串字串(j,i]存在字典中,则dp[i]为true;
遍历结束时将dp[s.length]return
为了更好的判断字串(j,i]是否在字典中,先将字典转换成set
java
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
HashSet<String> set = new HashSet<String>(wordDict);
boolean[] dp = new boolean[s.length()+1];
dp[0] = true;
for(int i=1;i<=s.length();++i){
for(int j=0;j <i;++j){
if(dp[j] && set.contains(s.substring(j,i))){
dp[i] = true;
break;//j这里不用再遍历了,从下一位i开始
}
}
}
return dp[s.length()];
}
}
时间: 击败了66.63%
内存: 击败了70.02%
322.零钱兑换
给你一个整数数组
coins
,表示不同面额的硬币;以及一个整数amount
,表示总金额。计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回
-1
。你可以认为每种硬币的数量是无限的。
【输入样例】coins =[1, 2, 5]
, amount =11
【输出样例】3
11=5+5+1
解题思路:
定义数组dp[i],表示凑足总额为i所需的最高硬币个数
寻找规律,凑足金额为i-coins[j]的最少个数为dp[i-coins[j]],那么只需要加上一个硬币coins[j]即可获得dp[i],dp[i]取小min(dp[i],dp[i-coins[j]]+1);
数组初始化,凑如总金额为0所需的钱币个数为0,dp[0]=0,其余的dp[i]下标为最大值,因为要进行min操作
java
class Solution {
public int coinChange(int[] coins, int amount) {
int max = Integer.MAX_VALUE;
int[] dp = new int[amount+1];
//初始化数组
for(int i = 1; i< amount+1;++i){
dp[i] = max;
}
dp[0] = 0;
for(int j = 0;j < coins.length;++j){
//从这个钱币开始
for(int i = coins[j]; i <=amount; ++i){
if(dp[i-coins[j]] != max){
dp[i] = Math.min(dp[i],dp[i-coins[j]]+1);
}
}
}
return dp[amount] == max ? -1 : dp[amount];
}
}
时间: 击败了45.96%
内存: 击败了19.52%
300.最长递增子序列
给你一个整数数组
nums
,找到其中最长严格递增子序列的长度。子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,
[3,6,2,7]
是数组[0,3,1,6,2,2,7]
的子序列。
【输入样例】nums = [10,9,2,5,3,7,101,18]【输出样例】4
[2,3,7,101]
解题思路:
定义数组dp[i],表示i之前包括i的以nums[i]结尾的最长递增子序列的长度
位置i的最长递增子序列等于j从0到i-1各个位置的最长递增子序列+1的最大值
dp[i]的默认大小为1,就是只选择本身的情况
java
class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
int res = 1;
for(int i=0;i<nums.length;++i){
dp[i] = 1;
}
for(int i = 1; i < nums.length; ++i){
for(int j = 0;j < i; ++j){
if(nums[i] > nums[j]){
//递增子序列,所以要大才可以计算
dp[i] = Math.max(dp[i],dp[j]+1);
}
res = Math.max(dp[i],res);
}
}
return res;
}
}
时间: 击败了25.90%
内存: 击败了15.18%