0%

数组类算法笔记

数组类算法笔记(双指针)

数组类算法笔记(双指针)

1.两数之和 II - 输入有序数组

给定一个已按照 非递减顺序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。

函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

1
2
3
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
  • 暴力解法 时间复杂度O(n^2)

  • unordered_map

    unoered_map底层由哈希表实现,索引的查找时间复杂度为O(1),利用这个性质,一层循环即可实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class Solution
    {
    public:
    unordered_map<int, int> m;
    vector<int> twoSum(vector<int> &numbers, int target)
    {
    for (int i = 0; i < numbers.size(); i++)
    {
    if (m.count(target - numbers[i]))
    {
    return {m.at(target - numbers[i]), i + 1};
    }
    else
    {
    m.emplace(numbers[i], i + 1);
    }
    }
    return {};
    }
    };
  • 对撞指针

    两个指针分别指向最小最大数,并不断向中间靠拢。

    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
    class Solution
    {
    public:
    vector<int> twoSum(vector<int> &numbers, int target)
    {
    int n = numbers.size() - 1;
    int i = 0;
    while (i < n)
    {
    if (numbers[i] + numbers[n] == target)
    {
    return {i + 1, n + 1};
    }
    else if (numbers[i] + numbers[n] < target)
    {
    i++;
    }
    else if (numbers[i] + numbers[n] > target)
    {
    n--;
    }
    }
    return {};
    }
    };

2.验证回文串

给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。

说明:本题中,我们将空字符串定义为有效的回文串。

  • isalnum()判断一个字符是否是字母或数字

    int isalnum ( int c );

    isalnum() 函数用来检测一个字符是否是字母或者十进制数字。

    如果仅仅检测一个字符是否是字母,可以使用 isalpha() 函数;如果仅仅检测一个字符是否是十进制数字,可以使用 isdigit() 函数。

    如果一个字符被 isalpha() 或者 isdigit() 检测后返回“真”,那么它被 isalnum() 检测后也一定会返回“真”。

    标准 ASCII 编码共包含了 128 个字符,不同的字符属于不同的分类,我们在 [ctype.h](http://c.biancheng.net/ref/ctype_h/) 头文件中给出了详细的列表。

    1
    2
    3
    4
    5
    示例 1:

    输入: "A man, a plan, a canal: Panama"
    输出: true
    解释:"amanaplanacanalpanama" 是回文串

3.长度最小的子数组

  • 暴力破解法

    时间复杂度 $O(n^2)$,从头到尾遍历所有满足>=target的子数组,并将最短长度返回。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    int minSubArrayLen(int target, vector<int>& nums) {
    int i = 0;
    int j ;
    int sum;
    int length = nums.size()+1;
    for (int i = 0;i<nums.size();i++){
    sum = nums[i];
    if(sum>=target) return 1;
    for (j=i+1;j<nums.size();j++){
    sum += nums[j];
    if(sum>=target&&(j-i+1)<length){
    length = j - i + 1;
    }
    }
    }
    return length==nums.size()+1?0:length;
    }
    • 滑动窗口法

      减少了每次重新定位右侧边界的时间。先不断增大右侧边界以达到target,再不断缩减左侧边界以保证最小长度。近遍历一次数组并随时存储满足target的最小长度。

      时间复杂度$O(2n)$,空间复杂度$O(1)$。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      int minSubArrayLen(int target, vector<int>& nums) {
      int i = 0;
      int j = 0;
      int sum = 0;
      int length = nums.size()+1;
      while (j<nums.size())
      {
      sum += nums[j];
      while(sum >= target){
      length = min(length,j-i+1);
      sum -= nums[i];
      i++;
      }
      j++;
      }
      return length==nums.size()+1?0:length;
      }

4.二维数组 旋转矩阵

给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 90 度。

不占用额外内存空间能否做到?

image-20220227103311271

  • 借助辅助矩阵 (空间复杂度 $O(N^2)$)
1
2
3
4
5
6
7
8
9
10
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
vector<vector<int>> newMatix = matrix;//此处数组的拷贝是值拷贝 获得一个新的数组
for (int i = 0;i<n;i++){
for (int j = 0;j<n;j++){
newMatix[j][n-1-i] = matrix[i][j];
}
}
matrix = newMatix;//此处同样是值拷贝
}
  • 每次旋转4个位置 空间复杂度$O(1)$

    image-20220227105639686

image-20220227105700261

关键变换:image-20220227105728343

代入4次:

image-20220227105750529

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for (int i = 0;i<n/2;i++){// n为奇数的n-1/2 == n为偶数的n/2
for (int j = 0;j<(n+1)/2;j++){//n为奇数的n+1/2 == n为偶数的n/2
int temp;
temp = matrix[i][j];
matrix[i][j] = matrix[n-j-1][i];
matrix[n-j-1][i] = matrix[n-i-1][n-1-j];
matrix[n-i-1][n-1-j] = matrix[j][n-1-i];
matrix[j][n-1-i] = temp;
}
}
return;
}
  • 对称2次 空间复杂度$O(1)$

image-20220227110155841

image-20220227110238605

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for (int i = 0;i<n/2;i++){
for (int j = 0;j<n;j++){
swap(matrix[i][j],matrix[n-1-i][j]);
}
}
for (int i = 0;i<n;i++){
for (int j = 0;j<i;j++){
swap(matrix[i][j],matrix[j][i]);
}
}
return;
}
void swap(int& a,int& b){
int temp;
temp = a;
a = b;
b = temp;
}

5.零矩阵

编写一种算法,若M × N矩阵中某个元素为0,则将其所在的行与列清零。

  • 空间复杂度$O(n^2)$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
vector<int> row(m), col(n);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (!matrix[i][j]) {
row[i] = col[j] = true;
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (row[i] || col[j]) {
matrix[i][j] = 0;
}
}
}
}
};
  • 空间复杂度$O(1)$ 2个存储空间

    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    void setZeroes(vector<vector<int>>& matrix) {
    int n = matrix.size();
    int m = matrix[0].size();
    int row = 0;
    int col = 0;
    for(int i = 0;i<n;i++){
    if(!matrix[i][0]){
    row = 1;
    }
    }
    for(int j = 0;j<m;j++){
    if(!matrix[0][j]){
    col = 1;
    }
    }
    for(int i = 1;i<n;i++){
    for(int j = 1;j<m;j++){
    if(!matrix[i][j]){
    matrix[i][0] = 0;
    matrix[0][j] = 0;
    }
    }
    }
    for(int i = 1;i<n;i++){
    for(int j = 1;j<m;j++){
    if((!matrix[0][j])||(!matrix[i][0])){
    matrix[i][j] = 0;
    }
    }
    }
    if(row){
    for(int i =0;i<n;i++){
    matrix[i][0] = 0;
    }
    }
    if(col){
    for(int j = 0;j<m;j++){
    matrix[0][j] = 0;
    }
    }
    }

空间复杂度$O(1)$ 1个存储空间

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
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
int flag_col0 = false;
for (int i = 0; i < m; i++) {
if (!matrix[i][0]) {
flag_col0 = true;
}
for (int j = 1; j < n; j++) {
if (!matrix[i][j]) {
matrix[i][0] = matrix[0][j] = 0;
}
}
}
for (int i = m - 1; i >= 0; i--) {
for (int j = 1; j < n; j++) {
if (!matrix[i][0] || !matrix[0][j]) {
matrix[i][j] = 0;
}
}
if (flag_col0) {
matrix[i][0] = 0;
}
}
}