我的leetcode学习之旅第三周——第一部分 从记忆化搜索入门动态规划

从记忆化搜索入门动态规划

引导题目:Triangle
给定一个数字三角形,找到从顶部到底部的最小路径和。每一步可以移动到下面一行的相邻数字上。
[1]
[23]
[456]
这种结构的特点是中间的数字可能从不同的路径访问到。因此可以保存到该点的最小路径和。
四种解决方案:1、Traverse 2、Divide Conquer 3、Traditional Dynamic Programming

class Solution {
public:
    /**
     * @param triangle: a list of lists of integers.
     * @return: An integer, minimum path sum.
     */
    int minimumTotal(vector<vector<int> > &triangle) {
        // write your code here
        if (triangle.size() == 0)
            return 0;
            
        vector<int> f(triangle[triangle.size()-1].size());
        //f[] 代表每个点所在位置的最小的总和,下一层直接调用就可以。
        f[0] = triangle[0][0];
        for(int i = 1; i < triangle.size(); i++)
            for(int j = triangle[i].size() - 1; j >= 0; j--)
            	// 下一行的最左边,只有一条路径能访问,直接上一层最小值加上该点值
                if (j == 0)
                    f[j] = f[j] + triangle[i][j];
                // 下一行的最右边,只有一条路径能访问,直接上一层最小值加上该点值
                else if (j == triangle[i].size() - 1)
                    f[j] = f[j-1] + triangle[i][j];
                //  下一行中间的某个点,判断它上面连接的两个点哪个和小,选它并加上该点值。
                else
                    f[j] = min(f[j-1], f[j]) + triangle[i][j];
                    
        int ret = INT_MAX;
        for(int i = 0; i < f.size(); i++)
            ret = min(ret, f[i]);
        return ret; 
    }
};

记忆化搜索可以将指数级别时间复杂度降低到多项式级别,记忆化搜索本质就是动态规划。

不适用DP的三个场景:求所有的具体方案,输入序列无序,暴力算法时间复杂度已经是多项式级别。
例题:Palindrome Partitioning 求出具体方案
给定字符串 s, 需要将它分割成一些子串, 使得每个子串都是回文串.返回所有可能的分割方案.
思路:用DFS就行

class Solution {
public:
    vector<vector<string>> partition(string s) {
        vector<vector<string>> res;
        vector<string> cur;
        dfs(s,cur,res);
        return res;
    }
 
    bool isPalindrome(string s){
        return s==string(s.rbegin(),s.rend());
    }
 
    void dfs(string s,vector<string> &cur,vector<vector<string>> &res){
        if (s==""){
            res.push_back(cur);
            return;
        }
 
        for (int i = 1; i <= s.length(); ++i) {
            string sub=s.substr(0,i);
            if (isPalindrome(sub)){
                cur.push_back(sub);
                dfs(s.substr(i,s.length()-i),cur,res);
                cur.pop_back();
            }
        }
 
    }
};

如果只求出一个具体方案,可以加入DP
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。返回符合要求的最少分割次数。

class Solution {
public:
    int minCut(string s) {
        int len=s.length();

        // 状态定义:dp[i]:前缀子串 s[0:i] (包括索引 i 处的字符)符合要求的最少分割次数
        int dp[len];

        // 1 个字符最多分割 0 次;
        // 2 个字符最多分割 1 次;
        // 3 个字符最多分割 2 次
        // 初始化的时候,设置成为这个最多分割次数
        for(int i=0;i<len;i++){
            dp[i]=i;
        }

        //创建二维数组用于记录子串s[a:b]是否为回文串,且一开始全部初始化为false(可以发现a<=b)
        vector<vector<bool>> checkPalindrome(len, vector<bool>(len, false));
        
        //根据所给的字符串s,遍历,记录子串s[a:b]是否为回文串
        for(int right=0;right<len;right++){
            for(int left=0;left<=right;left++){
                if(s[left]==s[right] && (right-left<=2 || checkPalindrome[left+1][right-1])){ // "right-left<=2" 和 "checkPalindrome[left+1][right-1]"位置不可换
                    checkPalindrome[left][right]=true;
                }
            }
        }

        // 状态转移方程:
        // dp[i] = min(dp[j] + 1 if s[j + 1: i] 是回文 for j in range(i))
        for(int i=0;i<len;i++){
            if(checkPalindrome[0][i]){
                dp[i]=0;
                continue;
            }
            for(int j=0;j<i;j++){
                if(checkPalindrome[j+1][i]){
                    dp[i]=min(dp[i],dp[j]+1);
                }
            }
        }

        return dp[len-1];
    }
};

输入数据是无序的:最长连续序列
给定一个未排序的整数数组,找出最长连续序列的长度。
时间复杂度:for循环n次,while整个也只会运行n次,O(n+n) = O(n)

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        if(nums.empty()){
            return 0;
        }
        unordered_set<int> myset(nums.begin(), nums.end());
        int res = 0;
        
        for(auto num : nums){
            // 如果集合内 num-1 个数为0,表示num是连续数组的开头,则运行
            if(myset.count(num-1)==0){
                int x = num + 1;
                // 当后面有数字,x++
                while(myset.count(x)){
                    x ++;
                }
                // 保存最长的个数
                res = max(res, x-num);
            }
        }
        return res;
    }
};

暴力算法的复杂度已经是多项式级别:柱状图中最大的矩形(难题)
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。求在该柱状图中,能够勾勒出来的矩形的最大面积。
常规思路要O(n^3),下面栈的思路为O(n)

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        stack<int> s;
        s.push(-1);
        int max_area = 0, height, width;
        for(int i = 0; i < heights.size(); ++i) {
            while(s.top() != -1 && heights[i] <= heights[s.top()]) {
                height = heights[s.top()];
                s.pop();
                width = i-s.top()-1;
                //cout<<"height:"<<height<<" width:" <<width<<endl;
                max_area = max(max_area, width*height);
                //cout<<max_area<<endl;
            }
            s.push(i);
        }
        while(s.top() != -1) {
            height = heights[s.top()];
            s.pop();
            width = heights.size() - s.top() - 1;
            max_area = max(max_area, width*height);
            //cout<<max_area<<endl;
        }
        return max_area;
    }
};

作者:wallcwr
链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/solution/dan-diao-di-zeng-zhan-by-wallcwr/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

适用DP的三个场景:求最值,求方案总数,求可行性。(都是很宽泛的一个结果)

题目:Wildcard Matching 通配符匹配 (双序列型动态规划)
判断两个可能包含通配符“?”和“”的字符串是否匹配。匹配规则如下:
‘?’ 可以匹配任何单个字符。
'
’ 可以匹配任意字符串(包括空字符串)。
两个串完全匹配才算匹配成功。

class Solution {
public:
    /**
     * @param s: A string 
     * @param p: A string includes "?" and "*"
     * @return: A boolean
     */
    bool isMatch(const char *s, const char *p) {
        if (s == NULL || p == NULL) {
            return false;
        }
        // 字符串转bool 
        int n = strlen(s);
        int m = strlen(p);
        int f[n + 1][m + 1];
        // f 填充 false
        memset(f, false, sizeof(f));
        
        f[0][0] = true;
        // f[][0] 全部填充false
        for (int i = 1; i <= n; i++)
            f[i][0] = false;
        // f[0][] 填充false
        for (int i = 1; i <= m; i++)
            f[0][i] = f[0][i - 1] && p[i - 1] == '*';
        
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (p[j - 1] == '*') {
                    f[i][j] = f[i - 1][j] || f[i][j - 1];
                } else if (p[j - 1] == '?') {
                    f[i][j] = f[i - 1][j - 1];
                } else {
                    f[i][j] = f[i - 1][j - 1] && (s[i - 1] == p[j - 1]);
                }
            }
        } // for
        
        return f[n][m];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值