IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 贪心算法和动态规划 -> 正文阅读

[数据结构与算法]贪心算法和动态规划

人们认识事物的方法有三种:通过概念(即对事物的基本认识)、通过判断(即对事物的加深认识)、和推理(对事物的深层认识)。其中,推理又包含归纳法和演绎法。(这些从初中高中一直到大学我们都是一直在学习的,关键是理解)

归纳法是从特殊到一般,属于发散思维;(如:苏格拉底会死;张三会死;李四会死;王五会死……,他们都是人。所以,人都会死。)

演绎法是从一般到特殊,属于汇聚思维。(如:人都会死的;苏格拉底是人。所以,苏格拉底会死。)

贪心:

贪心法:是指从问题的初始状态出发,通过若干次的贪心选择而得出最优值(或较优值)的一种解题方法。贪心策略总是做出在当前看来是最优的选择,也就是说贪心策略并不是从整体上加以考虑,它所作出的选择只是在某种意义上的局部最优解。(贪心在很多情况下往往是不合适的,所以对于刷题我并不建议使用弹性算法,用动态规划就挺好)

零钱兑换:

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回?-1 。

你可以认为每种硬币的数量是无限的。

输入:coins = [1, 2, 5], amount = 11
输出:3 
解释:11 = 5 + 5 + 1

如果我们用贪心思想,每次取最大的数额的硬币,那么6,1,1,1,1,5,5,5凑成10,我们可能可能会陷入一种局部最优,但是并不是我们想要的结果?

public class coinChange {
    /**
     * 问题最好硬币数组成一个数
     * 硬币面额一定,数量不一定
     * f(要组成的面额)=最小组成总数的硬币数量
     *假设我们知道 F(S) ,即组成金额 S 最少的硬币数,最后一枚硬币的面值是 C
     *F(S)=F(S?C)+1
     *那问题就转化成了求F(S-C)
     * 由于我们不知道c是多少,所以我们要枚举枚举每个硬币面额值,并选择其中的最小值min(F(S-ci))
     * @param coins
     * @param amount
     * @return
     */
    public int coinChange(int[] coins, int amount) {
        if(amount == 0) return 0;
        if(amount<0){
            return  -1;
        }
        int[] dp = new int[amount+1];//最多的硬币情况是全部是1元,共有amount个硬币.其实这里不一定是+1,+多少都可以。只要dp不可能取都值即可
        Arrays.fill(dp, amount+1);//必须将所有的dp赋最大值,因为要找最小值
        dp[0] = 0;//自底向上,金额为0,最小硬币数为0。当输入当金额是0当说话,肯定是0;
        for(int am = 1; am <= amount; am++) {//自底向上
            for (int coin : coins) {//遍历coins的金额
                if (am >= coin) {//只有总金额大于当前当面值当时候才继续
                    dp[am] = Math.min(dp[am], dp[am-coin] + 1);//金额为11的最小硬币数 和 金额为(11-一个面值)的最小硬币数+1 比较最小值
                
                }
            }
        }
        return dp[amount]>amount? -1: dp[amount];//
        }
}

打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

示例 1:

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
?? ? 偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:

输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
?? ? 偷窃到的最高金额 = 2 + 9 + 1 = 12 。

/**
 * 输入是每个房间的金额
 * 问题是求能偷到到最大值
 * 约束是不能偷相邻的方便
 * f(0)=0
 * f(1)=nums[1]
 * f(2)=max(f(1),f(0)+nums[1])
 * f(3)=max(f(2),f(1)+nums[2])
 * f(4)=max(f(3),f(2)+nums[3])
 * 那么我们可以得出一个转移方程,这个看起来可以用递归,但是递归会有很多重复计算 不如直接做
 */
public class rob {
    
    public int rob(int[] nums) {
        int [] dp=new int[nums.length+1];
        
        if(nums==null){
            return 0;
        }
        if (nums.length==1){
            return nums[0];
        }
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0], nums[1]);
        for (int i = 2; i <nums.length ; i++) {
            dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
        }
    
        return dp[nums.length - 1];
    
    }
}

做几道之后发现动态规划好想还是不是很难哈,但是问题是要怎么识别这是一个动态规划能解决的问题。

来来来再看一道

最长有效括号

给你一个只包含 '('?和 ')'?的字符串,找出最长有效(格式正确且连续)括号子串的长度。

示例 1:

输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"
示例 2:

输入:s = ")()())"
输出:4
解释:最长有效括号子串是 "()()"
示例 3:

输入:s = ""
输出:0

/*
   看到这个题目的第一印象,,用栈
   然后就是我们要保存前面的遍历结果。
   最先想到的当然暴力法,每个都遍历一边,比较最大。
   我压根没想到这居然也是一道动态规划的问题
 */
   public int longestValidParentheses(String s) {
        Deque<Integer> stack = new LinkedList<>();
        int max = 0;
        //为了保持一致性,避免边界条件处理
        stack.push(-1);
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i)=='('){
                //入栈
                stack.push(i);
            }else {
                //出栈
                stack.pop();
                if (stack.isEmpty()) {
                    stack.push(i);
                }else {
                    max =Math.max(max,i-stack.peek());
                }
            }
            
        }
        return max;
    }

/**
动态规划解法,虽然这道题我肯定不会有动态规划去解决,因为什么? 想不到哈哈哈

*/
class Solution {
    public int longestValidParentheses2(String s) {
        int maxans = 0;
        int[] dp = new int[s.length()];
        for (int i = 1; i < s.length(); i++) {
            if (s.charAt(i) == ')') {
                if (s.charAt(i - 1) == '(') {
                    dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
                } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
                    dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2;
                }
                maxans = Math.max(maxans, dp[i]);
            }
        }
        return maxans;
    }
}

未完待续。。。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-09-02 11:37:50  更:2021-09-02 11:39:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/30 1:10:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码