左神算法中级班第八课[C++代码]

声明:博客根据左神在毕站的讲课视频整理,代码是根据左神的java代码版本改写为c++版本
代码为自己动手改写,未经应用不能转载

github代码链接:
https://github.com/hjfenghj/zuoshen_middlecalss

第三题:纯code递归[百度原题,难]

递归,把把问题分为小问题
在这里插入图片描述

  • 思路
    假设数组Arr=[a,b,c,…,z],然后a为位置1,z为位置26

f(i,len)表示从位置i的字符出发,长度len的字符串的种类数
g(len)表示长度为len的字符串种类数

所以给一个字符串str
首先计算长度小于str.size()的字符串有多少个;
然后根据str的首字符在Arr的位置k1,计算位置k以前的字符为起始,长度为str.size()的字符串个数;
然后根据字符串str的第二个字符位置k2,计算以位置k2以前的字符为起始,长度为str.size()-1的字符个数;依次类推

代码

  • code
#include<iostream>
#include<vector>
#include<string>

using namespace std;

class PROBLEM03
{
public:
	//以idx字符开始,长度为Len的字符串的数量,,idx表示字符在[a,...,Z]中的位置
	int f(int idx, int Len)
	{
		int sum = 0;
		if (Len == 1)
			return 1;

		for (int i = idx+1; i <= 26; i++)
		{
			sum += f(i, Len-1);
		}
		return sum;
	}
	//得到长度为len的字符串有几个
	int g(int len)
	{
		int sum = 0;
		for (int i = 1; i <= 26; i++)
			sum += f(i, len);
		return sum;
	}
	int process(string str)
	{
		int ans = 0;
		int L = str.size();
		for (int i = 1; i < L; i++)
		{
			ans += g(i);
		}

		int first = str[0] - 'a' + 1;
		for (int i = 1; i < first; i++)
			ans += f(i,L);


		int pre = first;
		for (int i = 1; i < L; i++)
		{
			int newL = str[i] - 'a' + 1;
			for (int j = pre + 1; j < newL; j++)
			{
				ans += f(j, L - i);
			}
			pre = newL;
		}
		return ans + 1;
	}
};

int main()
{
	string str = "ab";
	PROBLEM03 P;
	int ans = P.process(str);
	cout << ans << endl;
	return 0;
}

第四题:最长无重复字符串的长度

技巧:动态规划,类似于最长有效括号字符串

  • 思路
    看代码了解思想把,很简单的思路,但是不好描述

代码

  • code
#include<iostream>
#include<vector>
#include<map>
using namespace std;

class PROBLEM03_1
{
public:
	int get_res(string str)
	{
		vector<int> dp(str.size(), 0);
		dp[0] = 1;
		int ans = INT_MIN;
		for (int i = 1; i < str.size(); i++)
		{
			int j = 1;
			bool flag = true;//是否在dp[i-1]的影响范围内,找到Arr[i]
			while (j <= dp[i-1])
			{
				if (str[i - j] == str[i])
				{
					dp[i] = j;
					flag = false;
					break;
				}
				j++;
			}
			if(flag)
				dp[i] = dp[i - 1] + 1;

			ans = max(ans, dp[i]);
		}
		return ans;
	}
};

//pre代表i-1结尾的最长无重复字串的长度,在i位置更新dp[i]的时候
//如果dp[i-1]影响的范围内出现了arr[i].那么dp[i] = i - temp;
//如果dp[i-1]影响的范围内没有出现arr[i],那么dp[i] = i-temp,这时候的temp就是dp[i-1]包含的小区域前的一个,i位置的dp[i]也不能跳过影响
class PROBLEM03_2
{
public:
	int get_res(string str)
	{
		map<int,int> M; //储存每一个字符上一个出现的位置,所有字符的ascii范围是0-255
		for (int i = 0; i < 256 ; i++)
		{
			M[i] = -1;
		}

		int pre = -1;//i位置往前跳dp[i]步到达的位置
		int cur = 0;//字符上一次出现的位置
		int ans = INT_MIN;
		for (int i = 0; i < str.size(); i++)
		{
			pre = max(pre, M[str[i]]);//距离i位置近的位置,作为新的pre
			ans = max(ans, i - pre);
			M[str[i]] = i;
		}
		return ans;
	}
};

int main()
{
	string str = "abcabcbb";
	PROBLEM03_2 P;
	int ans = P.get_res(str);
	cout << ans << endl;
	return 0;
}

第五题:字符转换最小代价

动态规划,力扣72的变种
在这里插入图片描述

代码

  • code
#include<iostream>
#include<vector>
#include<string>

using namespace std;

class PROBLEM05
{
public:
	int ic;
	int dc;
	int rc;
	PROBLEM05(int i, int d, int r)
	{
		ic = i;
		dc = d;
		rc = r;
	}

	int get_res(string str1, string str2)
	{
		int L1 = str1.size();
		int L2 = str2.size();
		vector<vector<int>> dp(L1+1, vector<int>(L2+1, 0));
		dp[0][0] = 0;

		for (int i = 1; i <= L2; i++)
			dp[0][i] = ic * i;
		for (int i = 1; i <= L1; i++)
			dp[i][0] = dc * i;

		for (int i = 1; i <= L1; i++)
		{
			for (int j = 1; j <= L2; j++)
			{
				
				//仿照力扣72题的思路,力扣72是求操作数;
				if (str1[i-1]-str2[j-1] == 0)
					dp[i][j] = min(dp[i - 1][j] + dc, min(dp[i][j - 1] + ic, dp[i - 1][j - 1]));
				else
					dp[i][j] = min(dp[i - 1][j] + dc, min(dp[i][j - 1] + ic, dp[i - 1][j - 1]+rc));
			}
		}
		return dp[L1][L2];
	}
};

int main()
{
	string s1 = "abd";
	string s2 = "add";
	PROBLEM05 P(5,3,2);
	int ans = P.get_res(s1,s2);
	cout << ans << endl;
	return 0;
}

第六题:最小字典序

在这里插入图片描述

  • 思路
    1)遍历字符串,记录词频
    2)重新遍历,词频表实时显示剩余没遍历的字符中的词频,当词频表中某字符词频变为零的时候停止遍历,去遍历过的元素中ACSII最小的字符ch,并删除整个数组中的字符ch
    3)重复1和2

代码

#include<iostream>
#include<vector>
#include<string>
#include<map>

using namespace std;

class PROBLEM06
{
public:
	string process(string str)
	{
		if (str.size() == 1)
			return str;

		//统计词频
		map<char, int> M;
		for (char s : str)
		{
			M[s]++;
		}

		int idx = 0;

		for (int i=0;i<str.size();i++)
		{
			idx = str[idx] - '0' > str[i] - '0' ? i : idx;//记录经过的字符中acsii最小的字符的位置
			if (--M[str[i]] == 0)
				break;
		}
		string s(1, str[idx]);
		string new_str(str.begin() + idx + 1, str.end());
		new_str.erase(remove(new_str.begin(), new_str.end(), str[idx]), new_str.end());
		return  s + process(new_str);
	}
};

int main()
{
	string str = "dbcacbca";
	PROBLEM06 P;
	string ans = P.process(str);
	cout << ans << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星光技术人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值