算法--动态规划

1.给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案 


package algorithm.dtgh;

/**

 * @version BiTeWei.java, v 0.1 2022年01月27日 16:09
 * 给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。
 * 输入:n = 2
 * 输出:[0,1,1]
 * 解释:
 * 0 --> 0
 * 1 --> 1
 * 2 --> 10
 */
public class BiTeWei {
    public static int[] countBits(int n) {
        //动态规划
        int[] bits = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            bits[i] = bits[i & (i - 1)] + 1;
        }
        return bits;
    }
    public static int[] countBits1(int n) {
        int[] bits = new int[n + 1];
        for (int i = 0; i <= n; i++) {
            bits[i] = Integer.bitCount(i^0);
        }
        return bits;
    }


    public static void main(String[] args) {
        int[] ints = countBits(4);
        for (int anInt : ints) {
            System.out.println(anInt);
        }
        System.out.println("------------------");
        int[] ints1 = countBits1(4);
        for (int anInt : ints1) {
            System.out.println(anInt);
        }
    }
}

 

2.给定一个数组 prices ,它的第i 个元素prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润


package algorithm.dtgh;

/**

 * @version BuyStocks.java, v 0.1 2022年01月27日 15:08
 *给定一个数组 prices ,它的第i 个元素prices[i] 表示一支给定股票第 i 天的价格。
 * 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润
 * 返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
 */
public class BuyStocks {
    public static int maxProfit(int[] prices) {
        int maxProfit = 0;
        int min = prices[0];
        for (int price : prices) {
           if(price < min){
               min = price;
           }else{
               maxProfit = Math.max(maxProfit, price - min);
           }
        }
        return maxProfit;
    }

    public static void main(String[] args) {
        int[] arry = new int[]{7,1,5,3,6,4};
        int[] arry1 = new int[]{1,1,5,3,6,10};
        System.out.println(maxProfit(arry1));
    }
}

取的最大利润  返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

3. 爬楼梯 ,假设你正在爬楼梯。需要 n阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?


package algorithm.dtgh;

/**

 * @version ClimbStairs.java, v 0.1 2022年01月26日 16:07
 * 爬楼梯
 * 假设你正在爬楼梯。需要 n阶你才能到达楼顶。
 * 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
 * 示例 1:
 * 输入:n = 2
 * 输出:2
 * 解释:有两种方法可以爬到楼顶。
 * 1. 1 阶 + 1 阶
 * 2. 2 阶
 * 示例 2:
 * 输入:n = 3
 * 输出:3
 * 解释:有三种方法可以爬到楼顶。
 * 1. 1 阶 + 1 阶 + 1 阶
 * 2. 1 阶 + 2 阶
 * 3. 2 阶 + 1 阶
 *
 * 思路:
 * 动态规划
 * n = 1: case = 1
 * n = 2: case = 2
 * n = 3: case = (1+2) = 3
 * n = 4: case = (2+3) = 5
 * n = 5: case = (3+5) = 8
 */
public class ClimbStairs {
    public static int climbStairs(int n) {
        if(n <=2) return n;
        int count = 1;
        int pre1 = 2;
        int pre2 = 1;
        for(int i = 3 ; i <= n; i++){
            count = pre1 + pre2;
            pre2 = pre1;
            pre1 = count;
        }
        return count;
    }

    public static int climbStairs1(int n) {
        int[] arr = new int[n];
        if(n <=2) return n;
        arr[0] = 1;
        arr[1] = 2;
        for(int i = 2 ; i < n; i++){
            arr[i] = arr[i-1] + arr[i-2];
        }
        return arr[n-1];
    }


    public static void main(String[] args) {
        //System.out.println(climbStairs(3));
        System.out.println(climbStairs1(5));
    }
}

4.给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。


package algorithm.dtgh;

/**

 * @version CostClimbingStairs.java, v 0.1 2022年01月29日 10:07
 * 给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。
 * 你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。
输入:cost = [10,15,20]
输出:15
解释:你将从下标为 1 的台阶开始。
- 支付 15 ,向上爬两个台阶,到达楼梯顶部。
总花费为 15
输入:cost = [10,15,20,3,44,5,1,3,2]
 */
public class CostClimbingStairs {
    public static int minCostClimbingStairs(int[] cost) {
        //动态规划
        int pre1 = cost[0];
        int pre2 = cost[1];
        int curr = 0;
        for(int i = 2 ; i < cost.length ; i++){
            curr = cost[i]+Math.min(pre1,pre2);
            pre1 = pre2;
            pre2 = curr;
        }
        return  Math.min(pre1,pre2);

    }

    public static void main(String[] args) {
        System.out.println(minCostClimbingStairs(new int[]{1,100,1,1,1,100,1,1,100,1}));
    }
}

 5.小扣打算给自己的 VS code 安装使用插件,初始状态下带宽每分钟可以完成 1 个插件的下载。假定每分钟选择以下两种策略之一:  使用当前带宽下载插件  将带宽加倍(下载插件数量随之加倍) *请返回小扣完成下载 n 个插件最少需要多少分钟。  注意:实际的下载的插件数量可以超过 n 个


package algorithm.dtgh;

/**

 * @version DownLoadPlugin.java, v 0.1 2022年01月26日 14:40
 * 小扣打算给自己的 VS code 安装使用插件,初始状态下带宽每分钟可以完成 1 个插件的下载。假定每分钟选择以下两种策略之一:
 * 使用当前带宽下载插件
 * 将带宽加倍(下载插件数量随之加倍)
 * 请返回小扣完成下载 n 个插件最少需要多少分钟。
 * 注意:实际的下载的插件数量可以超过 n 个
 * 示例 1:
 * 输入:n = 2
 * 输出:2
 * 解释:
 * 以下两个方案,都能实现 2 分钟内下载 2 个插件
 * 方案一:第一分钟带宽加倍,带宽可每分钟下载 2 个插件;第二分钟下载 2 个插件
 * 方案二:第一分钟下载 1 个插件,第二分钟下载 1 个插件
未用动态规划方法  直接用的数学方法
 */
public class DownLoadPlugin {
    public static int leastMinutes(int n) {
        int loadNum = 1;
        int times = 0;
        while(loadNum < n){
            loadNum = 2*loadNum;
            times ++;
        }
        times += 1;
        return times;
    }

    public static void main(String[] args) {
        System.out.println(leastMinutes(5));
    }

}

6.斐波那契数 (通常用 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


package algorithm.dtgh;

/**

 * @version Fib.java, v 0.1 2022年01月28日 17:38
 * 斐波那契数 (通常用 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
 */
public class Fib {
    public static int fib(int n) {
        //递归
        if( n == 0 ){
            return 0;
        }else if(n == 1){
            return 1;
        }else{
            return fib(n-1) + fib(n -2);
        }
    }

    public static int fib1(int n) {
        //使用动态规划
        if(n < 2){
            return n;
        }
        int pre1 = 0 ;
        int pre2 = 0 ;
        int result = 1;
        for(int i = 2 ; i <= n ; i++){
            pre2 = pre1;
            pre1 = result;
            result = pre1 + pre2;
        }

        return result;
    }

    public static void main(String[] args) {
        System.out.println(fib(6));
        System.out.println(fib1(6));
    }
}

7.输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6 连续子数组 [4,-1,2,1] 的和最大,为 6 。


package algorithm.dtgh;

/**

 * @version MaxSubarraySum.java, v 0.1 2022年01月26日 15:19
 * 输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
 * 输出:6
 * 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
 * 动态规划:动态规划求出的是最优状态,所以必然也是针对状态的操作,
 * 而状态自然可以出现在最优解中,也可以不出现——这便是决策的特性(布尔性)
 * 动态规划也有无后效性,即每个当前状态会且仅会决策出下一状态,而不直接对未来的所有状态负责
 */
public class MaxSubarraySum {
    public static int maxSubArray(int[] nums) {
        int  max = nums[0];
        int sum = max;
        for (int num : nums) {
            if(sum > 0 ){
                sum +=num;
            }else{
                sum = num;
            }
            max = Math.max(max,sum);
        }
        return max;
    }

    public static void main(String[] args) {
        System.out.println(maxSubArray(new int[]{-2,1,-3}));
    }
}

8.给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。


package algorithm.dtgh;

/**

 * @version Subsequence.java, v 0.1 2022年01月28日 16:50
 * 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
 * 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
 * 进阶:
 * 如果有大量输入的 S,称作 S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码
 * 输入:s = "abc", t = "ahbgdc"
 * 输出:true
 *
 * 输入:s = "axc", t = "ahbgdc"
 * 输出:false
 *需要使用双指针的方式
 */
public class Subsequence {
    public static boolean isSubsequence(String s, String t) {
        int i = 0 ;
        int j = 0;
        int sLen = s.length();
        int tLen = t.length();
        while(i < sLen && j < tLen){
            if(s.charAt(i) == t.charAt(j)){
                i++;
            }
                j++;
        }
        return i == sLen;
    }

    public static void main(String[] args) {
        System.out.println(isSubsequence("ace", "abcde"));
    }
}

9.在「杨辉三角」中,每个数是它左上方和右上方的数的和。  输入: numRows = 5  

 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]


package algorithm.dtgh;

import java.util.ArrayList;
import java.util.List;

/**

 * @version YangHuiSanJiao.java, v 0.1 2022年01月26日 17:00
 * 给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。
 *
 * 在「杨辉三角」中,每个数是它左上方和右上方的数的和。
 * 输入: numRows = 5
 * 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
 * 动态规划:下一步的操作基于上一步 所以叫动态规划吗  ??
 * 1、动态规划类似数学的已知fn-1求fn;
 * 2、已知f1 = 1,每一行第一个和最后一个数为1,中间数为其左上方和右上方的数的和;
 * 3、求得的fn记得添加到result中。
 */
public class YangHuiSanJiao {
    public static List<List<Integer>> generate(int numRows) {
        List<List<Integer>> result = new ArrayList<>();
        for (int i = 0 ; i < numRows ;i++){
            List<Integer> list = new ArrayList<>();
            for(int j = 0 ; j <= i ; j++){
                if(j == 0 || j == i){
                    list.add(1);
                }else{
                    list.add(result.get(i -1).get(j-1)+result.get(i-1).get(j));
                }
            }
            result.add(list);
        }
        return result;
    }

    public static void main(String[] args) {
        List<List<Integer>> result = generate(8);
        result.forEach(integers -> System.out.println(integers));
    }
}

10.

给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行。

 在「杨辉三角」中,每个数是它左上方和右上方的数的和


package algorithm.dtgh;

import java.util.ArrayList;
import java.util.List;

/**

 * @version YangHuiSanJiao1.java, v 0.1 2022年01月27日 14:31
 * 给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行。
 * 在「杨辉三角」中,每个数是它左上方和右上方的数的和。
 * 输入: rowIndex = 3
 * 输出: [1,3,3,1]
 *
 * 输入: rowIndex = 1
 * 输出: [1,1]
 */
public class YangHuiSanJiao1 {
    public static List<Integer> getRow(int rowIndex) {
        int[] dp = new int[rowIndex];
        for(int i = 0 ;i < rowIndex ; i++){
            for(int j = i;j >= 0; j--){ //防止覆盖,选择从右到左填入值
                if(j == 0 || j == i){
                    dp[j] = 1;
                }else{
                    dp[j] = dp[j-1] + dp[j];
                }
            }
        }
        //转换返回值
        List<Integer> res = new ArrayList<>(dp.length);
        for(int n: dp){
            res.add(n);
        }
        return res;
    }

    public static void main(String[] args) {
        System.out.println(getRow(4));
        System.out.println(getRow1(4));
    }

    public static List<Integer> getRow1(int rowIndex) {
        List<List<Integer>> result = new ArrayList<>();
        for (int i = 0 ; i < rowIndex ;i++){
            List<Integer> list = new ArrayList<>();
            for(int j = 0 ; j <= i ; j++){
                if(j == 0 || j == i){
                    list.add(1);
                }else{
                    list.add(result.get(i -1).get(j-1)+result.get(i-1).get(j));
                }
            }
            result.add(list);
        }
        return result.get(rowIndex-1);
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值