持续更新中.....................................
斐波那契数 (通常用 F(n)
表示)形成的序列称为 斐波那契数列 。该数列由 0
和 1
开始,后面的每一项数字都是前面两项数字的和。也就是:F(0) = 0,F(1) = 1 F(n) = F(n - 1) + F(n - 2),其中 n > 1。
示例:输入:n = 2 输出:1 解释:F(2) = F(1) + F(0) = 1 + 0 = 1
class Solution {
public int fib(int n) {
if(n < 2){
return n;
}
int[] dp = new int[n + 1];
dp[0] = 0;
dp[1] = 1;
for(int i = 2; i <= n; i++){
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}
假设你正在爬楼梯。需要 n
阶你才能到达楼顶。每次你可以爬 1
或 2
个台阶。你有多少种不同的方法可以爬到楼顶呢?
示例:输入:n = 2 输出:2
class Solution {
public int climbStairs(int n) {
if(n <= 2){
return n;
}
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
for(int i = 3; i <= n; i++){
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}
给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。请你计算并返回达到楼梯顶部的最低花费。
示例:输入:cost = [1,100,1,1,1,100,1,1,100,1] 输出:6
class Solution {
public int minCostClimbingStairs(int[] cost) {
int n = cost.length;
int[] dp = new int[n + 1];
dp[0] = 0;
dp[1] = 0;
for(int i = 2; i <= n; i++){
dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
}
return dp[n];
}
}
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。问总共有多少条不同的路径?
示例:输入:m = 3, n = 7 输出:28
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
//初始化
for(int i = 0; i < m; i++){
dp[i][0] = 1;
}
for(int j = 0; j < n; j++){
dp[0][j] = 1;
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
}
}
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?网格中的障碍物和空位置分别用 1 和 0 来表示。
示例:输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]] 输出:2
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] dp = new int[m][n];
for(int i = 0; i < m && obstacleGrid[i][0] == 0; i++){
dp[i][0] = 1;
}
for(int j = 0; j < n && obstacleGrid[0][j] == 0; j++){
dp[0][j] = 1;
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
if(obstacleGrid[i][j] == 0){
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}else{
dp[i][j] = 0;
}
}
}
return dp[m - 1][n - 1];
}
}
给定一个正整数 n
,将其拆分为 k
个 正整数 的和( k >= 2
),并使这些整数的乘积最大化。返回 你可以获得的最大乘积 。
示例:输入: n = 10 输出: 36 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
class Solution {
public int integerBreak(int n) {
int[] dp = new int[n + 1]; //dp[i] 为正整数 i 拆分后的结果的最大乘积
dp[2] = 1;
for(int i = 3; i <= n; i++){
for(int j = 1; j <= i - j; j++){
// (i - j) * j 是单纯的把整数 i 拆分为两个数 也就是 i,i-j ,再相乘
// dp[i - j] * j 是将 i 拆分成两个以及两个以上的个数,再相乘。
dp[i] = Math.max(dp[i], Math.max((i - j) * j, dp[i - j] * j));
}
}
return dp[n];
}
}
给你一个整数 n
,求恰由 n
个节点组成且节点值从 1
到 n
互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
class Solution {
public int numTrees(int n) {
int[] dp = new int[n + 1];
//初始化0个节点和1个节点的情况
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i <= n; i++){
for(int j = 1; j <= i; j++){
//对于第i个节点,需要考虑 1 作为根节点直到 i 作为根节点的情况,所以需要累加
//一共i个节点,对于根节点 j 时,左子树的节点个数为j-1,右子树的节点个数为i-j
dp[i] += dp[j - 1] * dp[i - j];
}
}
return dp[n];
}
}
有n件物品和一个最多能背重量为bagSize的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,问背包能背的物品最大价值是多少?
示例:输入:weight = [1, 3, 4]; value = [15, 20, 30]; bagsize = 4; 输出:35
class Solution{
public int bagProblem(int[] weight, int[] value, int bagSize) {
int[][] dp = new int[weight.length][bagSize + 1];
// 初始化dp数组
for(int j = weight[0]; j <= bagSize; j++) {
dp[0][j] = value[0];
}
for(int i = 1; i < weight.length; i++){
for(int j = 1; j <= bagSize; j++){
if(j < weight[i]){
dp[i][j] = dp[i - 1][j]; //当前背包的容量都没有当前物品i大的时候,则不放物品i
}else{
//比较 不放物品i 和 放物品i 这两种情况下,哪种背包中物品的价值最大
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
}
return dp[weight.length - 1][bagSize];
}
}
class Solution{
public int bagProblem(int[] weight, int[] value, int bagSize) {
int[] dp = new int[bagSize + 1]; //dp[j]表示背包容量为j时,能获得的最大价值
for(int i = 0; i < weight.length; i++){
for(int j = bagSize; j >= weight[i]; j--){
dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
}
}
return dp[bagSize];
}
}
给你一个 只包含正整数 的 非空 数组 nums
。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例:输入:nums = [1,5,11,5] 输出:true
class Solution {
public boolean canPartition(int[] nums) {
int sum = Arrays.stream(nums).sum();
if(sum % 2 != 0){
return false;
}
//转化为01背包问题:选取的数字的和恰好等于整个数组的元素和的一半
int target = sum / 2;
boolean[][] dp = new boolean[nums.length][target + 1];
//初始化dp
if(nums[0] <= target){
dp[0][nums[0]] = true;
}
for(int i = 1; i < nums.length; i++){
for(int j = 1; j <= target; j++){
if(j < nums[i]){
dp[i][j] = dp[i - 1][j];
}else{
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]];
}
}
}
return dp[nums.length - 1][target];
}
}
class Solution {
public boolean canPartition(int[] nums) {
int sum = Arrays.stream(nums).sum();
if(sum % 2 != 0){
return false;
}
//转化为01背包问题:选取的数字的和恰好等于整个数组的元素和的一半
int target = sum / 2;
boolean[] dp = new boolean[target + 1];
//初始化dp
if(nums[0] <= target){
dp[nums[0]] = true;
}
for(int i = 1; i < nums.length; i++){
for(int j = target; j >= nums[i]; j--){
dp[j] = dp[j] || dp[j - nums[i]];
}
}
return dp[target];
}
}
有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:
如果 x == y,那么两块石头都会被完全粉碎;
如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0。
示例:输入:stones = [2,7,4,1,8,1] 输出:1
class Solution {
public int lastStoneWeightII(int[] stones) {
//石头的总重量为sum, ki=-1的石头的重量之和为neg,则其余ki=1的石头的重量之和为sum−neg
//则结果为:ki * stones[i]的累加和 = (sum - neg) - neg = sum - 2 * neg
//要使最后一块石头的重量尽可能地小, neg需要在不超过 ⌊sum/2⌋ 的前提下尽可能地大
//本问题可以看作是背包容量为 ⌊sum/2⌋,物品的重量与价值均为stones[i]的0-1背包问题。
int sum = Arrays.stream(stones).sum();
int target = sum / 2;
int[][] dp = new int[stones.length][target + 1];
//初始化dp数组
for(int j = stones[0]; j <= target; j++){
dp[0][j] = stones[0];
}
for(int i = 1; i < stones.length; i++){
for(int j = 1; j <= target; j++){
if(j < stones[i]){
dp[i][j] = dp[i - 1][j];
}else{
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - stones[i]] + stones[i]);
}
}
}
return sum - 2 * dp[stones.length - 1][target];
}
}
class Solution {
public int lastStoneWeightII(int[] stones) {
int sum = Arrays.stream(stones).sum();
int target = sum / 2;
int[] dp = new int[target + 1];
for(int i = 0; i < stones.length; i++){
for(int j = target; j >= stones[i]; j--){
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
return sum - 2 * dp[target];
}
}