0%

剑指 Offer 05. 替换空格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
string replaceSpace(string s){
int count=0;//统计空格的个数
int sOldSize = s.size();
for(int i=0;i<s.size();i++){
if(s[i]==' '){
count++;
}
}
//扩充字符串s的大小,也就是每个空格替换成"%20"之后的大小
s.resize(s.size()+count*2);
int sNewSize=s.size();
//从后向前将空格替换成"%20"
for(int i=sNewSize-1,j=sOldSize-1;j<i;i--,j--){
if(s[j]!=' '){
s[i]=s[j];
}else{
s[i]='0';
s[i-1]='2';
s[i-2]='%';
i-=2;
}
}
return s;
}

541. 反转字符串 II

reverse is 左闭右开 每隔k个就反转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
string reverseStr(string s,int k){
for(int i =0;i<s.size();i+=(2*k)){
//每隔2k个字符的前k个字符进行反转
//剩余字符小于2k 但大于或等于k个,则反转前k个字符
// abcdefg
// bacdfeg
//0+2<7
// reverse 0,2 ba
// i=4
// 4+2<=7
// reverse 4,6 ef
if(i+k<=s.size()){
reverse(s.begin()+i,s.begin()+i+k);
}
else{
//剩余字符串少于k个,则将剩余字符全部反转
reverse(s.begin()+i,s.end());
}
}
return s;
}

自己写一个左闭右闭的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void reverse(string& s,int start,int end){
for(int i=start,j=end;i<j;i++,j--){
swap(s[i],s[j]);
}
string reverseStr(string s,int k ){
for(int i =0;i<s.size();i+=(2*k)){
if(i+k<=s.size()){
reverse(s,i,i+k-1);
continue;
}
reverse(s,i,s.size()-1;)
}
return s;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
void reverse(string& s,int start,int end){
for(int i=start,j=end;i<j;i++,j--){
swap(s[i],s[j]);
}
}
string reverseStr(string s, int k) {
for(int i =0;i<s.size();i+=(2*k)){
if(i+k<=s.size()){
reverse(s,i,i+k-1);
}
else{
reverse(s,i,s.size()-1);
}
}
return s;
}
};

18. 四数之和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
vector<vector<int>> fourSum(vector<int>& nums,int target){
vector<vector<int>> result;
sort(nums.begin(),nums.end());//排序
for(int k = 0;k<nums.size();k++){
//剪枝处理
if(nums[k]>target&&num[k]>=0) break; //你这个数都大于target了(前提是这个玩意儿是>0的)
//对nums[k]去重复
if(k>0&&nums[k]==nums[k-1]){
continue;
}
for(int i = k+1;i<nums.size();i++){
//2级剪枝处理
if(nums[k]+nums[i]>target&&nums[k]+nums[i]>=0) break;
//对nums[i]去重
if(i>k+1&&nums[i]==nums[i-1]) continue;
int left=i+1;
int right=nums.size()-1;
while(right>left){
if((long)nums[k]+nums[i]+nums[left]+nums[right]>target) right--;
else if((long)nums[k]+nums[i]+nums[left]+nums[right]<target) left++;
else result.push_back(vector<int>{nums[k],nums[i],nums[left],nums[right]});
while(right>left&&nums[right]==nums[right-1])right--;
while(right>left&&nums[left]==nums[left+1]) left++;
right--;
left++;
}
}
}
return result;
}

15. 三数之和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
vector<vector<int>> threeSum(vector<int>& nums){
vector<vector<int>> result;
sort(nums.begin(),nums.end());
//找出a+b+c=0
//a=nums[i],b=nums[left],c=nums[right]
for(int i = 0 ;i<nums.size();i++){
//排序之后如果第一个元素已经大于0,那么无论如何都不可能组成三元组了
if(nums[i]>0){
return result;
}
//i去重
if(i>0&&nums[i]==nums[i-1]){
continue;
}
int left=i+1;
int right=nums.size()-1;
while(right>left){
if(nums[i]+nums[left]+nums[right]>0) right--;
else if(nums[i]+nums[left]+nums[right]<0) left++;
else{
result.push_back(vector<int>{nums[i],nums[left],nums[right]});
while(right>left&&nums[right]==nums[right-1]) right--;
while(right>left&&nums[left]==nums[left+1]) left++;
right--;
left++;
}
}
}
return result;
}

383. 赎金信

暴力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bool canConstruct(string ransomNote,string magazine){
for(int i =0;i<magazine.length();i++){
for(int j = 0;j<ransomNote.length();j++){
//在ransomNote中找到和magazine相同的字符
if(magazine[i]==ransomNote[j]){
ransomNote.erase(ransomNote.begin()+j);
break;
}
}
}
if(ransomNote.length()==0){
return true;
}
return false;
}

哈希

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
bool canConstruct(string ransomNote,string magazine){
int record[26]={0};
if(ransomNote.size()>magazine.size()){
return false;
}
for(int i=0;i<magazine.length();i++){
record[magazine[i]-'a']++;
}
for(int j =0;j<ransomNote.length();j++){
record[ransomNote[j]-'a']--;
if(record[ransomNote[j]-'a']<0){
return flae;
}
}
return true;
}

for(int a :nums1) 是 C++11 中引入的一种新的循环语法,称为范围 for 循环(range-based for loop),用于方便地遍历容器中的元素。

在这个语法中,nums1 是一个容器,a 是一个变量,表示容器中的每个元素。循环语句会依次遍历容器中的每个元素,并将当前元素赋值给变量 a,然后执行循环体中的语句,直到遍历完所有元素。

以下是一个使用范围 for 循环遍历 vector 容器中的元素的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <vector>
using namespace std;

int main()
{
vector<int> nums = {1, 2, 3, 4, 5};
for (int num : nums) {
cout << num << " ";
}
cout << endl;
return 0;
}

在这个例子中,我们定义了一个包含整数的 vector 容器 nums,然后使用范围 for 循环遍历 nums 容器中的每个元素,并将当前元素赋值给 num 变量,然后输出 num 的值。在执行循环语句后,输出结果为:1 2 3 4 5

需要注意的是,范围 for 循环可以用于遍历各种类型的容器,包括数组、vector、list、deque、set、map 等容器类型。在实际编程中,我们可以使用范围 for 循环来方便地遍历容器中的元素,以提高代码的可读性和可维护性。

454. 四数相加 II

1
2
3
4
5
int fourCount(vector<int>& A,vectot<int>& B,vector<int>& C,vector<int>& D){
unordered_map<int,int> umap;//key:a+b的数值,value:a+b数值出现的次数
//遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中

}

有关using

using 是 C++ 中的一个关键字,它有多种用途,主要包括以下几个方面:

  1. 别名声明:使用 using 关键字可以给一个类型、变量、函数、模板等起一个别名。例如:

    1
    2
    using IntVec = std::vector<int>; // using 别名声明
    IntVec vec = {1, 2, 3}; // 使用别名 IntVec 来声明 vector<int> 类型的变量

    上面的代码中,我们使用 using 关键字给 std::vector<int> 类型起了一个别名 IntVec,然后使用别名 IntVec 来声明一个 vector<int> 类型的变量 vec,从而简化了代码。

  2. 命名空间别名:使用 using namespace 可以给一个命名空间起一个别名。例如:

    1
    namespace my_ns = my_namespace::sub_namespace; // 命名空间别名

    上面的代码中,我们使用 using namespace 关键字给 my_namespace::sub_namespace 命名空间起了一个别名 my_ns,从而在后续的代码中可以使用 my_ns 来代替 my_namespace::sub_namespace

  3. 模板别名:使用 using 关键字可以给一个模板类型起一个别名。例如:

    1
    2
    3
    template <typename T>
    using MyVec = std::vector<T>; // 模板别名声明
    MyVec<int> vec = {1, 2, 3}; // 使用模板别名 MyVec 来声明 vector<int> 类型的变量

上面的代码中,我们使用 using 关键字给 std::vector<T> 类型起了一个模板别名 MyVec<T>,然后使用模板别名 MyVec<int> 来声明一个 vector<int> 类型的变量 vec,从而简化了代码。

需要注意的是,using 关键字的使用虽然可以简化代码,但过度使用可能会降低代码的可读性和可维护性。在使用 using 关键字时,应该尽量保持别名的清晰和语义明确,以便于代码的理解和维护。

有关于auto

auto 是 C++11 中引入的关键字,用于让编译器自动推导变量的类型。通过 auto 关键字,我们可以让编译器根据变量的初始值或表达式推导出变量的类型,从而省略变量类型的显式声明。

具体来说,auto 关键字可以用于以下几种情况:

  1. 自动推导变量类型:在变量声明时使用 auto 关键字,让编译器自动推导变量的类型。例如:

    1
    2
    3
    4
    auto x = 1; // 推导出 x 的类型为 int
    auto y = 3.14; // 推导出 y 的类型为 double
    auto z = "hello"; // 推导出 z 的类型为 const char*
    ​```
  2. 函数返回值类型自动推导:在函数定义时使用 auto 关键字,让编译器自动推导函数的返回值类型。例如:

    1
    2
    3
    4
    5
    auto add(int x, int y) -> int // 推导出函数返回值类型为 int
    {
    return x + y;
    }

    注意,这种用法需要在函数定义时使用尾置返回类型(trailing return type)语法。

  3. 迭代器类型自动推导:在使用迭代器时使用 auto 关键字,让编译器自动推导迭代器的类型。例如:

    1
    2
    3
    4
    for (auto it = vec.begin(); it != vec.end(); ++it)
    {
    // do something with *it
    }

在这个例子中,auto 关键字让编译器自动推导出 it 的类型为 std::vector<int>::iterator

需要注意的是,虽然 auto 关键字可以让代码更加简洁,但过度使用可能会降低代码的可读性和可维护性。在使用 auto 关键字时,应该尽量保持变量名的清晰和语义明确,以便于代码的理解和维护。

1
2
3
4
5
6
std::vector<int> vec = {1, 2, 3};
for (auto it = vec.begin(); it != vec.end(); ++it)
{
// do something with *it
}
在这个例子中,`auto` 关键字让编译器自动推导出 `it` 的类型为 `std::vector<int>::iterator`。
1
2
3
4
5
std::vector<int> vec = {1, 2, 3};
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it)
{
// do something with *it
}