文章目录
- 字符串(String)
- 专题:关于各种最长子串、子序列问题
- 300.求最长子序列
- 674.最长递增子串
- size
- substr方法:
- erase方法
- find方法
- 一个疑问????
- 字符范围
- 题目类型
- 例一:把一个0-1串进行排序,可以交换任意连个位置,最少交换的次数?
- 例二:删除一个字符串所有的a,并且复制所有的b。注:字符数组足够大(就在字符串上修改)
- 例三:一个字符串只包含\*和数字,请把它的\*号都放开头
- 例四:给定两个串a和b,问b是否是a的子串的变位词。例如a ="hello",b="lel","lle","ello"都可以,但"elo"不行。
- 例五:单词翻转:翻转句子中的全部单词,单次内容不变。如"I am a student."变为"student.a am I"
- 例六:一个字符串,找出第一个不重复的字符,如“abbbabcd”,则第一个不重复就是c
- 数组
- 例七:n个整数的无序数组,找到每个元素后面比它大的第一个数,要求时间复杂度为O(N)
- 一个数组中有若干正整数,将此数组划分为两个子数组,使得两个子数组各元素之和a,b的差最小,对于非法输入应该输出ERROR。
字符串(String)
专题:关于各种最长子串、子序列问题
300.求最长子序列
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if(nums.empty())return 0;
int len = nums.size();
vector<int> dp(len,1);
for(int i =1 ;i<len ;i++)
{
int temp = 0;
for(int j =0 ;j<i ;j++)
{
if(nums[j]<nums[i]) temp = max(temp,dp[j]);
}
dp[i] = temp + 1;
}
return *max_element(dp.begin(),dp.end());
}
};
俄罗斯套娃问题就是再这个基础之上做的
class Solution {
public:
static inline bool func(const vector<int>& a, const vector<int>& b)
{
if(a[0]<b[0])return true;
if(a[0]==b[0] && a[1]>b[1])return true;
return false;
}
int maxEnvelopes(vector<vector<int>>& envelopes) {
if(envelopes.empty())return 0;
sort(envelopes.begin(),envelopes.end(),func);
int len = envelopes.size();
vector<int> dp(len,1);
for(int i = 1 ;i< len ;i++)
{
int temp = 0;
for(int j = 0; j<i; j++)
{
if(envelopes[j][1]<envelopes[i][1])temp =max(temp,dp[j]);
}
dp[i] = temp + 1;
}
return *max_element(dp.begin(), dp.end());
}
};
674.最长递增子串
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
int n = nums.size();
if(n<=1) return n;
int res = 1, len=1;
for(int i=1; i<n; i++){
if(nums[i] > nums[i-1]) len+=1;
else len = 1;
res = max(len, res);//进行比较
}
return res;
}
std::string 可更改,也可以用[]提取字符,和char[]数组使用上区别不大;
size
专门针对stl里用的,char字符串数组用strlen()
substr方法:
substr(n,m) n为起点,m要注意是长度而不是结束点!
erase方法
erase(n,m) n为起点,m要注意是长度而不是结束点!
find方法
find(‘a’)寻找字符a,并返回找到位置,没找到返回-1
find(’’,n)从n开始找
一个疑问????
string s = "ajoibaivobaoibjoai";
//int len = s.size();
int n = s.find('a'); //l = 0
//cout << typeid(l).name() << endl;
bool k1 = (-1 < n );//正确
bool k2 = (-1 < s.find('a'));//错误
n和s.find(‘a’)明明是相等的,为什么将整个放入就不对了??必须定义这一个才行??
字符范围
8位
[-128.127]通常转换为unsigned [0,+255]
题目类型
字典序;
简单操作:插入删除旋转;
规则判断(罗马数字判断、整数合法、浮点数);
数字运算(大数加法、二进制加法);
排序交换(partition过程);
字符计数(hash)变位词;
匹配(正则表达式、全串匹配、KMP、周期判断);
动态规划(LCS、编辑距离、最长回文串);
搜索(单词变换、排列组合);
例一:把一个0-1串进行排序,可以交换任意连个位置,最少交换的次数?
int main()
{
string s = "011001010100101010";
int len = s.size();
int i = 0;
int j = len - 1;
int num = 0;//维护这个对象
//s[i];
//s[j];
//bool a = (s[i] == '0' );
while (i < j)
{
if (s[i] == '1' && s[j] == '0')
{
swap(s[i], s[j]);
num = num + 1;
i = i + 1;
continue;
}
else if (s[i] == '1' && s[j] == '1')
{
j = j - 1;
continue;
}
else if (s[i] == '0' && s[j] == '1')
{
i = i + 1;
j = j - 1;
continue;
}
else if (s[i] == '0' && s[j] == '0')
{
i = i + 1;
continue;
}
}
std::cout << num << endl;
//std::cout << 1 << endl;
return num;
//
}
使用了快排的思想,一个在左一个在右,要特别注意的一点是,从字符串取出的类型是字符,所以比较的时候要加‘0’和‘1’;
线性复杂度O(len)
例二:删除一个字符串所有的a,并且复制所有的b。注:字符数组足够大(就在字符串上修改)
int main()
{
string s = "ajoibaivobaoibjoai";
int n1 = s.find('a');
while (n1 > -1)
{
s.erase(n1,1);
n1 = s.find('a');
}
int len = s.size();
int m = 0;
int num = 0;
int n2 = s.find('b',m);
//int m = 0;
while (n2 > -1 && m < len)
{
num = num + 1;
m = n2 + 1;
n2 = s.find('b',m);
}
for (int i = 0 ; i < num ; i++)
{
s.push_back('b');
}
cout << s << endl;
return 1;
//
}
1.首先要能够正确使用erase和push_back两个方法;
2.在对字符串进行迭代过程中一定不能删除元素,不然会造成下表混乱
3.布尔类型要小心使用,多定义变量
例三:一个字符串只包含*和数字,请把它的*号都放开头
string s = "25478*798**698*98";
int len = s.size();
int n = s.find('*');
int num = 0;
int i = 0;
int j = len - 1;
while (i < j)
{
if (!isdigit(s[i]) && !isdigit(s[j])) { i = i + 1; }
if (!isdigit(s[i]) && isdigit(s[j])) { i = i + 1; j = j - 1; }
if (isdigit(s[i]) && !isdigit(s[j])) { swap(s[i], s[j]); num = num + 1; i = i + 1; j = j - 1; }
if (isdigit(s[i]) && isdigit(s[j])) { j = j - 1; }
}
cout << s << endl;
cout << num << endl;
return 1;
这是数字改变的情况,如果要求数字不变,则先遍历取的*的个数以及位置,再重新构造数组。
例四:给定两个串a和b,问b是否是a的子串的变位词。例如a =“hello”,b=“lel”,“lle”,"ello"都可以,但"elo"不行。
做法一:
string a = "affagahahhafhahah";
//string b = "opl";
string b = "ahf";
//当n=2则有2中可能,当n=3则有6种,n有n的阶乘种
set<char> s1;
int lena = a.size();
int lenb = b.size();
for (auto i : b)
{
s1.insert(i);
}
for (int j = 0; j < (lena - lenb); j++)
{
set<char> s2;
for (int c = 0; c < lenb; c++)
{
s2.insert(a[j+c]);
}
if (s1 == s2)
{
cout << "true" << endl;
return 1;
}
}
cout << "false" << endl;
//两个思路:思路1:求出字符串的所有变位词,然后形成集合,看b是否是,pass;思路2:求出b的所有情况,去a查找
//实时证明上面两种都极难写,而且是n方复杂度,写不出来就只能转变思路,用滑动窗口滑a,取出来的只要字符与b相同就可以!
做法二:哈希
string a = "affagahahhafhahah";
//string b = "opl";
string b = "ahf";
//哈希:26个英文字母对应一个长度26的哈希表,
int arr1[26] = {};
for (auto i : b)
{
arr1[i - 'a'] = arr1[i - 'a'] + 1;
}
int lena = a.size();
int lenb = b.size();
int num = 0;
for (int j = 0; j < lena - lenb; j++)
//int j = 10;
{
int arr2[26] = {};
for (int c = 0; c < lenb; c++)
{
arr2[a[j + c] - 'a'] = arr2[a[j + c] - 'a'] + 1;
}
//if (arr1[] == arr2[])
//{
// cout << "True" << endl;
//}
num = 0;
for (int v = 0; v < 16; v++)
{
if (arr1[v] == arr2[v])
{
num = num + 1;
}
//num = num + 1;
}
if (num == 16)
{
cout << "True" << endl;
return 1;
}
}
cout << "False" << endl;
return 1;
注意几点:
- ’b’- ‘a’ =1可以直接实现字母到数字的映射,这使哈希表的建立变得简单;
- 比较两个数字型的数组相等时,一定不能直接比较数组名字,因为名字代表的是首地址!对于数字型的只能去循环遍历,字符型的可以考虑strump函数。
- 滑动窗口和哈希表映射这种思想还是值得留意的
例五:单词翻转:翻转句子中的全部单词,单次内容不变。如"I am a student.“变为"student.a am I”
string s = "I am a student.";
//string s2 = "";
//string s3 = s2 + s.substr(2,2);
bool n;
int lens = s.size();
vector<int> myvec;
for (int i = 0;i<lens;i++)
{
n = isalpha(s[i]);
if (n == 0)
{
myvec.push_back(i);
continue;
}
}
string s1 = "";
vector<int>::iterator iter;
int lenv = myvec.size();
int a1 = 0;
int a2 = 0;
for (int j = 0; j < lenv-1; j++)
{
a1 = myvec.back();
myvec.pop_back();
a2 = myvec.back();
s1 = s1 + s.substr(a2 +1,a1-a2);
}
a1 = myvec.back();
myvec.pop_back();
a2 = 0;
s1 = s1 + s.substr(a2, a1-a2);
cout << s1 << endl;
1.涉及到动态变化时不能用arr,容器vector和list在用法和方法上差不多;
2.截取字符串记得使用substr方法;
3.有时可以不使用迭代器而只是用Push——back等常见函数;
4.判断字母isalpha判断数字isdigit
例六:一个字符串,找出第一个不重复的字符,如“abbbabcd”,则第一个不重复就是c
使用哈希的思想,建立256个bool数组array,初始都为false,从头开始扫描字符串,扫到一个,将以其ascii码为下标的元素置true。例如扫描到A的时候,执行:array[‘A’]=true。第二边扫描,扫到一个字母就以其ascii码为下标,去array数组中看其值,如果是true,返回改字母,如果是false,继续扫描下一个字母。
链接:https://www.nowcoder.com/questionTerminal/c979e5876acb4c05b22c85c89a347b5a
来源:牛客网
char firstNonDuplicate(std::string s) {
std::unordered_map<char, int> m;
for(auto c : s) ++m[c];
for(auto c : s) {
if(m[c] == 1) return c;
}
return 0; // '\0'
}
关于哈希表:
https://blog.csdn.net/Huang_JinXin/article/details/95785544
1.STL哈希表使用unordered_map
2.循环便利 for(auto i 😒)
3.++m[c],如果没有则创建,且初值为1,如果有则加1
数组
STL vector, [];
vector自动扩容;
数组下表做哈希计数;
数组与map;
给数组顺序;
例一:局部极小值:一个给定的不包含相同元素的整数数组,每个局部极小值的定义是一个值比左右相邻的都小的值,求一个局部极小值
vector<int> myvec = {3,5,2,5,23,4};
vector<int>::iterator iter;
int lenv = myvec.size();
for (auto iter = myvec.begin()+1; iter != myvec.end()-3; iter++)
{
if (*iter > *(iter + 1) && *(iter + 2) > *(iter + 1))
{
cout << *(iter+1) << endl;
return 1;
}
}
注意迭代器的定义使用和容器元素的提取
例二:给一个数组,找到从1开始第一个不在里面的正整数
//快速排序(从小到大)
void quickSort(int left, int right, vector<int>& arr)//这里的参数必须定义成引用类型才行,如果不传递引用,会生成一个同实参一样大的vector<int>对象。且不能修改实参的值
void quicksort(int left, int right, vector<int> &arr)
{
if (left >= right) { return; }
int i = left;
int j = right;
while (i < j)
{
while (arr[j] >= arr[left] && i < j) { j--; }
while (arr[i] <= arr[left] && i<j) { i++; }
if (i < j) { swap(arr[i], arr[j]); }
}
swap(arr[i], arr[left]);
quicksort(left, i-1,arr );//留意
quicksort(i+1, right,arr);
}
原文链接:https://blog.csdn.net/qq_28584889/article/details/88136498
学习快速排序
vector<int> myvec = {14,5,1,5,146,46,16,6,1,4,1,412,2,3,34,5,66,56};
//vector<int> myvec = {7,6,4};
//方法一:对于每一个正整数取遍历,pass
//方法二:先对数组排序,使用最快的排序方式
int lenv = myvec.size();
vector<int>::iterator i;
//vector<int>::iterator j;
int left = 0;
int right = lenv - 1;
quicksort(left,right,myvec);
//i = myvec.begin();
//int n = *i;
//int m = *(i+1);
//bool b1 = *(i + 1) != *i;
//bool b2 = *(i + 1) != *i + 1;
//bool b = (*(i + 1) != *i) || (*(i + 1) != *i + 1);
for (i = myvec.begin(); i != myvec.end()-1; i++)
{
cout << *i << endl;
if (*(myvec.begin()) != 1)
{
cout << "asdfasdfa 1" << endl;
return 1;
}
else
{
if ((*(i + 1) != *i) && (*(i + 1) != *i + 1))
{
cout<<"fsafsdfaaf "<<*(i)+1<<endl;
return 1;
}
}
}
cout << myvec.back() + 1 << endl;
例三:元素最大距离:给定一个整数数组,求把这些整数表示在数轴上,相邻两个数差的最大值
vector<int> myvec = {14,5,1,5,146,46,16,6,1,4,1,412,2,3,34,5,66,56};
//vector<int> myvec = {7,6,4};
//方法一:对于每一个正整数取遍历,pass
//方法二:先对数组排序,使用最快的排序方式
int lenv = myvec.size();
vector<int>::iterator i;
//vector<int>::iterator j;
int left = 0;
int right = lenv - 1;
quicksort(left,right,myvec);
int max = 0;
for (i = myvec.begin(); i != myvec.end() - 1; i++)
{
cout << *i << endl;
//max = *(i + 1) - *i;
if (max < (*(i + 1) - *i))
{
max = *(i + 1) - *i;
}
}
cout <<"max=" <<max << endl;
例四:只出现一次的数:一个数组,所有数字都出现了两次,只有两个数出现了一次,求着两个数。
//vector<int> myvec = {14,5,1,5,146,46,16,6,1,4,1,412,2,3,34,5,66,56};
vector<int> myvec = {7,5,7,6,2,6,2,8};
//方法一:对于每一个正整数取遍历,pass
//方法二:先对数组排序,使用最快的排序方式
int lenv = myvec.size();
vector<int>::iterator i;
//vector<int>::iterator j;
//int n = *(myvec.end()-1);
int left = 0;
int right = lenv - 1;
quicksort(left,right,myvec);
vector<int> res;
for (i = myvec.begin()+1; i != myvec.end() - 1; i++)
{
//cout << *i << endl;
if ((*(i - 1) != *i) && (*i != *(i + 1)))
{
res.push_back(*i);
}
}
if (*(myvec.begin()) != *(myvec.begin()+1)) { res.push_back(*(myvec.begin())); }
if (*(myvec.end()-1) != *(myvec.end()-2)) { res.push_back(*(myvec.end()-1)); }
for (vector<int>::iterator r = res.begin(); r != res.end(); r++)
{
cout<<*r<<endl;
}
要注意迭代器的end()不指向任何内容
例五:找出超过一半的数
//vector<int> myvec = {14,5,1,5,146,46,16,6,1,4,1,412,2,3,34,5,66,56};
vector<int> myvec = {7,5,7,6,2,6,2,8};
//方法一:对于每一个正整数取遍历,pass
//方法二:先对数组排序,使用最快的排序方式
int lenv = myvec.size();
//int n = myvec[3];
vector<int>::iterator i;
//vector<int>::iterator j;
//int n = *(myvec.end()-1);
int left = 0;
int right = lenv - 1;
quicksort(left,right,myvec);
if ((lenv % 2) == 0)
{
cout << myvec[lenv/2] << endl;
}
else
{
cout<<myvec[(lenv-1)/2]<<endl;
}
//for (i = myvec.begin() + 1; i != myvec.end() - 1; i++)
//{
//
//}
还可以用哈希做
例六:给定浮点数组a,求一个数组b,b[i] = a[0]*a[1]…a[i-1]*a[i+1]…a[n-1],不能使用除法,不能再开数组。
//vector<int> myvec = {14,5,1,5,146,46,16,6,1,4,1,412,2,3,34,5,66,56};
vector<int> a = {7,5,7,6};
//方法一:对于每一个正整数取遍历,pass
//方法二:先对数组排序,使用最快的排序方式
int lena = a.size();
//int n = myvec[3];
vector<int>::iterator i;
//vector<int>::iterator j;
//int n = *(myvec.end()-1);
//int left = 0;
//int right = lenv - 1;
//quicksort(left,right,myvec);
vector<int> b;
for (int c = 0; c < lena; c++)
{
int cheng = 1;
if (c == 0)
{
for (i = a.begin() + 1; i != a.end(); i++)
{
cheng = cheng * (*i);
}
b.push_back(cheng);
}
else if (c == lena -1)
{
for (i = a.begin() ; i != a.end()-1; i++)
{
cheng = cheng * (*i);
}
b.push_back(cheng);
}
else
{
for (i = a.begin(); i != a.begin() + c; i++)
{
cheng = cheng * (*i);
}
for (i = a.begin() + c + 1; i != a.end(); i++)
{
cheng = cheng * (*i);
}
b.push_back(cheng);
}
}
vector<int>::iterator j;
for (j = b.begin(); j != b.end(); j++)
{
cout<<*j<<endl;
}
例七:n个整数的无序数组,找到每个元素后面比它大的第一个数,要求时间复杂度为O(N)
借助一个栈(s),栈中的每个元素代表未找到右侧第一个大于当前元素的值的下标(比较拗口,就是还没确定右边谁比它大,把这个元素的下标放到栈中)。
-
先两两比较相邻的两个元素值(a, b),如果是a>=b,说明元素是逆序排列的,将a的下标压栈,继续前行
-
一直找到a<b的元素,b即为第一个大于a的元素,将a下标出栈。
-
检查栈中的每个值指向的元素c,如果c<b,说明b即为第一个大于c的元素,将c下标出栈。一直到栈为空或者c>=b为止。
vector<int> FindMax(vector<int> &num)
{
int len=num.size();
if(len==0) return {}; //空数组,返回空
vector<int> res(len,-1); //返回结果:初始化-1,表示未找到
stack<int> notFind; //栈:num中还未找到符合条件的元素索引
int i=0;
while(i<len) //遍历数组
{
//如果栈空或者当前num元素不大于栈顶,将当前元素压栈,索引后移
if(notFind.empty() || num[notFind.top()]>=num[i])
{
notFind.push(i++);
}
//有待处理元素,且num当前元素大于栈顶索引元素,符合条件,更新结果数组中该索引的值,栈顶出栈。
else
{
res[notFind.top()]=num[i];
notFind.pop();
}
}
return res;
}
一个数组中有若干正整数,将此数组划分为两个子数组,使得两个子数组各元素之和a,b的差最小,对于非法输入应该输出ERROR。
dfs法超时
void dfs(vector<int>& vt, vector<int>& path, int sum,int target,bool flag,int m,vector<int>& record)
{
if(flag)return;
if(sum==target/2){flag = true;record = path;return;}
if(sum>target/2)
{
if(abs(sum-target/2)<m){m = abs(sum-target/2);record = path;}
return;
}
for(int i = 0;i<vt.size();i++)
{
path.push_back(vt[i]);
sum += vt[i];
dfs(vt,path,sum,target,flag,m,record);
sum -= vt[i];
path.pop_back();
}
}
int main()
{
string s;
while(getline(cin,s))
{
int len = s.size();
bool b = true;
for(int i = 0;i<s.size();i++)
{
if(isdigit(s[i])==false && s[i]!=' ')
{b= false; break;}
}
if(!b){cout<<"ERROR"<<endl;continue;}
vector<int> vt;
int i =0;
int target = 0;
while (i < s.size())
{
if (s[i] == ' ') { i++; continue; }
else
{
int temp = 0;
while(i<s.size() && isdigit(s[i]))
{
temp = temp*10 + int(s[i]-'0');i++;
}
target += temp;
vt.push_back(temp);
}
}
vector<int> path,record;
bool flag = false;
dfs(vt,path,0,target,flag,INT_MAX,record);
int res = 0;
for(auto i:record){res+=i;}
cout<<res<<" "<<target-res<<endl;
}
return 0;
}