您的位置:首页 > 娱乐 > 明星 > 自学编程从哪里开始学_郴州房产网_搜索引擎最新排名_网络推广哪个平台好

自学编程从哪里开始学_郴州房产网_搜索引擎最新排名_网络推广哪个平台好

2025/5/12 5:59:22 来源:https://blog.csdn.net/2302_76739243/article/details/146923344  浏览:    关键词:自学编程从哪里开始学_郴州房产网_搜索引擎最新排名_网络推广哪个平台好
自学编程从哪里开始学_郴州房产网_搜索引擎最新排名_网络推广哪个平台好

题目一:完全平方数

问题描述

279. 完全平方数 - 力扣(LeetCode)

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,149 和 16 都是完全平方数,而 3 和 11 不是。

示例 1:

输入:n = 12
输出:3 
解释:12 = 4 + 4 + 4

示例 2:

输入:n = 13
输出:2
解释:13 = 4 + 9

提示:

  • 1 <= n <= 104

解题步骤

参照昨天写的零钱兑换思路,我们不难写出如下代码:

class Solution {
public:int numSquares(int n) {vector<int> dp(n+1,INT_MAX);dp[0]=0;for(int i=1;i<=n;i++){for(int j=0;j<=n;j++){int k=i*i;if(j>=k){dp[j]=min(dp[j],dp[j-k]+1);}}}return dp[n];}
};

i代表可选数字,k代表i所计算出的完全平方数,j代表背包容量

初始化数组为INT_MAX便于求最小值

dp[0]=0,特别设置为0,便于后续使用、计算

 遍历数字,挨个尝试,更新数组

不放入当前数字则dp值不变,放入则减去占用容量,加上1,

为了选取最小值用min函数在上面两种情况中取小

最后输入dp[n]即可

提交后发现用时很长,才意识到遍历条件上可以优化一下

我们要求和为n,那么这个i不需要遍历到n,

不然此时算出k=n*n,远超所需,

所以外层循环应该改为

for(int i=1;i*i<=n;i++)

同时内层的j初始值也应该改变,后续也不需要判断j是否大于等于k

省时又省力

for(int j=i*i;j<=n;j++) 

这样就大大减少了无用功 

完整代码如下!

code

class Solution {
public:int numSquares(int n) {vector<int> dp(n+1,INT_MAX);dp[0]=0;for(int i=1;i*i<=n;i++){for(int j=i*i;j<=n;j++){dp[j]=min(dp[j],dp[j-i*i]+1);}}return dp[n];}
};

题目二:单词拆分

问题描述

139. 单词拆分 - 力扣(LeetCode)

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true

注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

示例 1:

输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。

示例 2:

输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。注意,你可以重复使用字典中的单词。

示例 3:

输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
输出: false

提示:

  • 1 <= s.length <= 300
  • 1 <= wordDict.length <= 1000
  • 1 <= wordDict[i].length <= 20
  • s 和 wordDict[i] 仅由小写英文字母组成
  • wordDict 中的所有字符串 互不相同

解题步骤

看完题目,这题应该是有序的完全背包

但是我先试了一下最简单的逐字匹配

写出的代码如下

class Solution {

public:

    bool wordBreak(string s, vector<string>& wordDict) {

        int j=0;

        while(j<s.length()){

            for(int i=0;i<wordDict.size();i++){//单词

                int len=wordDict[i].length();

                if(s.substr(j,len)==wordDict[i]){//与当前单词匹配

                    j=j+len;//下一位!

                }

                else return false;//失配返回false

            }

        }

        return true;//执行结束返回true

    }

};

 但这样的代码存在严重的问题

我试图按顺序匹配 wordDict 中的单词,一旦匹配就跳到下一个位置,但这样会忽略其他可能的组合方式。

例如:

s = "catsandog"wordDict = ["cats", "dog", "sand", "and", "cat"]

可能会先匹配 "cats" 然后 "and",但剩下的 "og" 无法匹配,直接返回 false

而实际上正确的组合是 "cat" + "sand" + "dog"

我没有回溯机制在当前单词不合适的情况下返回尝试其它组合

所以呢

还是走动规五部曲吧!

1.确定dp数组下标及含义

还是使用一维数组dp,

j表示当前待匹配的字符串长度

dp[j]表示当前长度的字符串是否能在字典中找到单词拼接

最后需要返回的就是dp[n]到底为true还是false

vector<string> dp(n+1,false);//n表示s的长度

2.初始化

dp[0]=true

代表空字符串可以被拼接

其它都初始化为false,在初始化时顺手完成了!

3.遍历顺序

由于拼接过程是有序的,所以外层是背包,内层是单词

unordered_set<string> wordSet(wordDict.begin(), wordDict.end());

for(int j=1;j<n;j++){//0已经被初始化,从1开始即可

        for(const string& word:wordDict){//用迭代器遍历单词更方便

4.递推公式

 我们要做的操作是取出已经放入的单词,加入当前遍历到的单词,判断是否匹配

所以要判断

1.当前单词长度j 是否大于等于 待加入单词长度len

不然根本换不了啊!

2.取出后状态是否为true

如果拿出来一个单词,前面拼不起来,那不是白搭

3.加入单词与字符串是否匹配

都要加入肯定得匹配嘛

在以上都符合的情况下,我们才更新dp值为true

否则不做处理

if( j >= len && dp[j-len] == true && word==s.substr(j-len,len)){

        dp[j]=true;

        break;//找到一个匹配的就结束

}

 整理代码即可得到以下完整版!

code

class Solution {
public:bool wordBreak(string s, vector<string>& wordDict) {unordered_set<string> wordSet(wordDict.begin(), wordDict.end());int n = s.length();vector<bool> dp(n + 1, false);dp[0] = true; // 空字符串可以被表示for (int j = 1; j <= n; j++) {for (const string& word : wordDict) {int len = word.length();if (j >= len && dp[j - len] && s.substr(j - len, len) == word) {dp[j] = true;break; // 找到一个匹配即可}}}return dp[n];}
};

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com