文章目录
1两数之和
vector<int> twoSum(vector<int>& nums, int target) {
vector<int>ans;
for (int x = 0; x < nums.size(); x++)
{
for (int y = x + 1; y < nums.size(); y++)
{
if (nums[x] + nums[y] == target)
{
ans.push_back(x);
ans.push_back(y);
return ans;
}
}
}
return ans;
}
#include <iostream>
using namespace std;
#include <bits/stdc++.h>
vector<int>twoSum(vector<int>&nums,int target)
{
vector<int>ans;
for(int x=0;x<nums.size();x++)
{
for(int y=x+1;y<nums.size();y++)
{
if(nums[x]+nums[y]==target)
{
ans.push_back(x);//下标
ans.push_back(y);
return ans;
}
}
}
return ans;
}
int main() {
vector<int>nums={
1,2,3,4,5};
vector<int>ans;
ans=twoSum(nums,5);
cout<<ans[0]<<ans[1];
return 0;
}
2.整数反转
ps:负数取模之后还是负数
法1:
int reverse(long x) {
long max=2147483647,min=-2147483648;
if (x >max || x <min )
return 0;
long n=0;
while(x)
{
n=n*10+x%10;
x/=10;
}
if(n>max||n<min)
return 0;
return n;
}
法2:(没什么区别,只是用了自带的INT_MAX,是2的32次方-1,负数是2的32次方-2)
int reverse(int x) {
if (x >INT_MAX || x <INT_MIN )
return 0;
long n=0;
while(x)
{
n=n*10+x%10;
x/=10;
}
if(n>INT_MAX||n<INT_MIN)
return 0;
return n;
}
3.回文数
bool isPalindrome(long x) {
long ori = x;
if (x < 0)
return false;
long n = 0;
while (x)
{
n = n * 10 + x % 10;
x /= 10;
}
if (ori == n)
return true;
else
return false;
}
#include <iostream>
using namespace std;
#include <bits/stdc++.h>
int main() {
int x=-123,ans=0;
while(x!=0)
{
ans=ans*10+x%10;
x/=10;
}
cout<<ans;
return 0;
}
不用字符串的做法:
bool isPalindrome(int x) {
if (x < 0)
return false;
vector<int>nums;
while (x)
{
nums.push_back(x % 10);
x /= 10;
}
int j = size(nums)-1;
for (int i = 0; i < size(nums) / 2; i++,j--)
{
if (nums[i] != nums[j])
{
return false;
}
}
return true;
}
4.猜数字
int game(vector<int>& guess, vector<int>& answer) {
int count=0;
for(int i=0;i<3;i++)
{
if(guess[i]==answer[i])
{
count++;
}
}
return count;
}
5.分式化简
vector<int> fraction(vector<int>& cont) {
int num = cont.size()-1;
int up = 1, down = 0;
down = cont[num];
while (num)
{
int tempup=up;
up = down;
num--;
down = cont[num] * up + tempup;
}
return{
down,up };
}
6.罗马数字转整数
int romanToInt(string s)
{
int count = s.size(), ans = 0;
for (int i = 0; i < count; i++)
{
if (i + 1 >= count)
ans += translate(s[i],'b');
else
ans += translate(s[i],s[i + 1]);
}
return ans;
}
int translate(char c1, char c2 = 'b')
{
if (c1 == 'I')
{
if (c2 == 'V' || c2 == 'X')
return -1;
else
return 1;
}
if (c1 == 'V')
return 5;
if (c1 == 'X')
{
if (c2 == 'L' || c2 == 'C')
return -10;
else
return 10;
}
if (c1 == 'L')
return 50;
if (c1 == 'C')
{
if (c2 == 'D' || c2 == 'M')
return -100;
else
return 100;
}
if (c1 == 'D')
return 500;
if (c1 == 'M')
return 1000;
return 0;
}
哈希表做法
#include <iostream>
using namespace std;
#include <bits/stdc++.h>
int main() {
string s="MCMXCIV";
unordered_map<char,int>uom={
{
'I',1},{
'V',5},{
'X',10},{
'L',50},{
'C',100},{
'D',500},{
'M',1000}};
int ans=0;
for(int i=0;i<s.size();i++)
{
uom[s[i]]<uom[s[i+1]]?ans-=uom[s[i]]:ans+=uom[s[i]];
}
cout<<ans;
return 0;
}
7.最长公共前缀
substr(a,b)是从第a位开始取b位字符串
比如:
string s="abcdefghijk";
cout << s.substr(0,2);//输出ab
cout << s.substr(0,3);//输出abc
cout << s.substr(1,2);//输出bc
cout << s.substr(1,3);//输出bcd
cout << s.substr(3,2);//输出de
string longestCommonPrefix(vector<string>& strs) {
int strs_size = strs.size();
int minsize = 1000;
vector<char>answer;
int flag;
//找vector里最短的一个string,因为最长字串的最大长度不会超过这个最短string的size
for (int i = 0; i < strs_size; i++)
{
if (strs[i].size() < minsize)
{
minsize = strs[i].size();
flag = i;
}
}
if (strs_size > 0)
{
int count = 0;
for (int j = 0; j < minsize; j++)
{
char temps = strs[0][j];
for (int i = 0; i < strs_size; i++)
{
if (strs[i][j] != temps)//一旦出现不等的,就可以return答案了
return strs[0].substr(0, j);//从第0位开始取j位,比如j是2,就是从第零位开始取两个,j在数组里是第三个从第三个开始不取,所以是符合的
}
count++;
}
if (count==minsize)//最短那个string就已经是最长公共前缀
return strs[flag];
}
return "";//空
}
8.有效的括号(栈)
方法1:
bool isValid(string s) {
stack<char>c;
for (int i = 0; i<s.size(); i++)
{
if (s[i] == '(')
c.push(')');
else if (s[i] == '{')
c.push('}');
else if (s[i] == '[')
c.push(']');
else if (s[i] == ')'||s[i]=='}'||s[i]==']')
{
if (c.empty()||c.top() != s[i])
return false;
else
c.pop();
}
}
return c.empty();
}
方法2:(是方法1化简版)
bool isValid(string s) {
stack<char>c;
for (int i = 0; i<s.size(); i++)
{
if (s[i] == '(')
c.push(')');
else if (s[i] == '{')
c.push('}');
else if (s[i] == '[')
c.push(']');
else if (c.empty()||c.top() != s[i])
return false;
else
c.pop();
}
return c.empty();
}
c++中栈stack的使用
stack的基本操作有:(pop、top、empty后面记得加括号!!!)
①入栈:如s.push(x);
②出栈(删除栈顶):如 s.pop();
③访问栈顶:如s.top();
④判断栈空:如s.empty().当栈空时返回true。
⑤访问栈中的元素个数,如s.size();
9.删除排序数组中的重复项
int removeDuplicates(vector<int>& nums) {
sort(nums.begin(), nums.end());//排序
auto cf=unique(nums.begin(), nums.end());//unique会去掉排序容器中的重复元素,并返回尾地址。
//注意!!auto一定要赋初值!
nums.erase(cf, nums.end());//去除重复元素(去除了unique返回的尾地址到原来的尾地址之间的东西)
return nums.size();
}
//测试用例:
int main()
{
vector<int>nums = {
1,2,3,3,2,1,4,5,6,7,4,3,2 };
cout<<removeDuplicates(nums);
return 0;
}
方法2(会好很多):
直接用unique去除重复元素返回的尾地址,减去首地址,就是值
int removeDuplicates(vector<int>& nums) {
return unique(nums.begin(),nums.end())-nums.begin();
}
ps:erase()的使用在下一篇中有详细解释 : https://blog.csdn.net/weixin_44575911/article/details/107873836
10.移除元素
移除迭代器vector中间的元素
方法1:
int removeElement(vector<int>& nums, int val) {
for (auto it = nums.begin(); it != nums.end();)
{
if (*it == val)//判断元素条件
it=nums.erase(it);//erase() 返回的是删除此元素之后的下一个元素的迭代器,it的值要变,而且一定要写成这样,不能写成it++
else
it++;
}
return nums.size();
}
测试用例:
int main()
{
vector<int>nums = {
1,2,3,3,2,1,4,5,6,7,4,3,2 };
cout << removeElement(nums,3);
return 0;
}
方法2:(其实和方法1是一个意思)
int removeElement(vector<int>& nums, int val) {
for(int i=0;i<nums.size();i++){
if(nums[i]==val){
nums.erase(nums.begin()+i);
i--;
}
}
return nums.size();
}
11.实现strStr()、KMP
下面两种方法都挺好的
方法1:用库函数find()
int strStr(string haystack, string needle) {
if(needle.empty())
return 0;
int pos=haystack.find(needle);
return pos;
}
方法2:用暴力
int strStr(string haystack, string needle) {
if(needle.empty())
return 0;
int i=0,j=0;
while(haystack[i]!='\0'&&needle[j]!='\0')
{
if(haystack[i]==needle[j])
{
i++;
j++;
}
else
{
i=i-j+1;//减j是返回到试j之前的那位,加1是下一位
j=0;//不符合的话回到needle的最初那位
}
}
if(needle[j]=='\0')//找到了符合的
return i-j;
return -1;
}
12.搜索插入位置(二分法)
二分法:
int searchInsert(vector<int>& nums, int target) {
int size = nums.size();
int left = 0, right = size - 1;
if (size == 0)//防止下溢
return 0;
if (target > nums[size - 1])//target为最大数,必须要有这个if
return size;
while (left < right)
{
int mid = left + (right-left) / 2;
if (nums[mid] < target)//在右边
left = mid+1;
else
right = mid;
}
return left;//right和left都行,一样的
}
13.外观数列
递归法:
string countAndSay(int n) {
int num = 1;
char value = 1;//value一定要用char,不然会是49,因为1的ascll码是49
if (n == 1)
return to_string(1);
string old = countAndSay(n - 1);
string ns;
for (int i = 0; i < old.size(); i++)
{
int flag = 1;
while(flag==1)
{
value = old[i];
if (i + 1 < old.size()&&old[i] == old[i + 1])
{
num += 1;
i++;
}
else
{
ns += to_string(num) + value;
value = 1;
num = 1;
flag = 0;
}
}
}
return ns;
}
int main()
{
cout << countAndSay(4);
return 0;
}
14.最大自序和(动态规划)
动态规划法:
下面两个是一个意思,dp[i]是包括第i位在内的连续的最大子序和
①vector定义的时候没有(size)不太好,因为vector的dp没有定义初始长度,一开始不能直接dp[0],必须用push_back
int maxSubArray(vector<int>& nums) {
int size = nums.size();
vector<int>dp;//包括第i位在内的连续的最大子序和
dp.push_back(nums[0]);
int ans = nums[0];
for (int i = 1; i < nums.size(); i++)
{
dp.push_back(max(nums[i], dp[i - 1] + nums[i]));
ans = max(ans, dp[i]);
}
return ans;
}
int main()
{
vector<int>nums = {
-2,1,-3,4,-1,2,1,-5,4 };
cout << maxSubArray(nums);
return 0;
}
②vector定义的时候有(size)好一点,在vector的最右边用括号括起长度比如vectordp(20)这样初始化,就可以直接写dp[0]了
贪心法
int maxSubArray(vector<int>& nums) {
int size = nums.size();
int ans = nums[0];
int sum = nums[0];
for (int i = 1; i < nums.size(); i++)
{
//下面这个if放在前面是为了解决第一位是负数的问题
if (sum < 0)//如果总和已经小于0了,那再加一个数的话总和只会比那个数小
{
sum = 0;//重置为0,意思就是下一个循环就可以作为开头了
}
sum += nums[i];
ans = max(ans, sum);
}
return ans;
}
int main()
{
vector<int>nums = {
-2,1,-3,4,-1,2,1,-5,4 };
cout << maxSubArray(nums);
return 0;
}
在上面这题中两种方法比较: