跟着《代码随想录》刷题(一)——数组

前言

C语言刷题太麻烦了,尤其是后面的哈希表之类的,所以我又学习了一些C++的东西,做了一些C++的解答。

1.1 数组基础理论

(1)定义:数组是存储在连续内存空间相同类型数据的集合。

(2)注意:

  • 数组下标是从0开始的;
  • 数组在内存空间的地址是连续的。
    =>删除或增添数组元素难免要移动其他元素的地址

(3)数组中的元素不能删除,只能覆盖

1.2 二分查找

1.2.1 二分法介绍

(1)使用前提:数组元素是有序的。
(2)时间复杂度:O (log N)
(3)二分法的区间定义有两种:左闭右闭 [left, right]左闭右开 [left, right)

  • 左闭右闭 [left, right]

前提边界条件设置:

int left = 0;
int right = numsSize - 1; //尤其注意这里

补充:在求中点 mid 时,用位运算更好一点

int mid = left + ((right - left) >> 1);

有两点要注意:

while (left <= right) // 注意这里是 <=
if (nums[mid] < target) 
	left = mid + 1;
else if (nums[mid] > target) 
	right = mid + 1; // 注意这里有 + 1
else 
	return mid;
  • 左闭右开 [left, right)

前提边界条件设置:

int left = 0;
int right = numsSize; // 注意这里没有进行 - 1

有两点要注意:

while (left < right)  // 注意这里只是 < 
if (nums[mid] < target)
	left = mid + 1;
else if (nums[mid] > target) 
	right = mid; // 注意这里没有进行 + 1
else
	return mid;

1.2.2 相关题目推荐

704、二分查找

LeetCode:34.二分查找
在这里插入图片描述

  • 左闭右闭
int search(int* nums, int numsSize, int target){
    int left = 0, right = numsSize - 1;
    int middle;

    // 用的左闭右闭[left, right]
    while (left <= right) {
        middle = left + ((right - left) >> 1);
        if (nums[middle] > target) {
            // 注意这里
            right = middle - 1;
        }else if (nums[middle] < target) {
            left = middle + 1;
        }else {
            return middle;
        }
    }
    return -1;
}

(cpp)

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        int mid = 0;

        while (left <= right) {
            mid = left + ((right - left) >> 1);

            if (nums[mid] < target) {
                left = mid + 1;
            } else if (nums[mid] > target) {
                right = mid - 1;
            } else {
                return mid;
            }
        }

        return -1;
    }
};
  • 左闭右开
int search(int* nums, int numsSize, int target){
    int left = 0, right = numsSize; //注意这里没有 减一
    int middle = 0;

    // 左闭右开 [left, right)
    while (left < right) {
        middle = left + ((right - left) >> 1);

        if (nums[middle] > target) {
            // 注意这里
            right = middle;
        }else if (nums[middle] < target) {
            left = middle + 1;
        }else {
            return middle;
        }
    }
    return -1;
}

cpp

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size();
        int mid = 0;

        while (left < right) {
            mid = left + ((right - left) >> 1);

            if (nums[mid] < target)
                left = mid + 1;
            else if (nums[mid] > target)
                right = mid;
            else 
                return mid;
        }

        return -1;
    }
};

35、搜索插入位置

LeetCode:35.搜索插入位置

在这里插入图片描述

  • 暴力解法
int searchInsert(int* nums, int numsSize, int target){
    // 暴力解法
    for (int i = 0; i < numsSize; i++) {
        if (nums[i] >= target) {
            return i;
        }
    }
    return numsSize;
}
  • 二分法:左闭右闭
int searchInsert(int* nums, int numsSize, int target){
    // 二分法
    int left = 0, right = numsSize - 1;
    int middle = 0;

    // 左闭右闭 [left, right]
    while (left <= right) {
        middle = left + ((right - left) >> 1);

        if (nums[middle] > target) {
            right = middle - 1;
        }else if (nums[middle] < target) {
            left = middle + 1;
        }else {
            return middle;
        }
    }

    // 注意这里,如果target没在数组里面,是返回的right + 1
    return right + 1;
}

注意:这里返回 left 也是可以的
cpp

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        int mid = 0;

        while (left <= right) {
            mid = left + ((right - left) >> 1);

            if (nums[mid] < target)
                left = mid + 1;
            else if (nums[mid] > target)
                right = mid - 1;
            else 
                return mid;
        }

        return left;
    }
};
  • 二分法:左闭右开
int searchInsert(int* nums, int numsSize, int target){
    // 二分法
    int left = 0, right = numsSize; // 注意这里没有减一
    int middle = 0;

    // 左闭右开
    while (left < right) {
        middle = left + ((right - left) >> 1);

        if (nums[middle] > target) {
            right = middle;
        }else if (nums[middle] < target) {
            left = middle + 1;
        }else {
            return middle;
        }
    }
    // 注意这里返回的是 right
    return right;
}

注意:这里返回 left 也是可以的
cpp

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size();
        int mid = 0;

        while (left < right) {
            mid = left + ((right - left) >> 1);

            if (nums[mid] < target)
                left = left + 1;
            else if (nums[mid] > target)
                right = mid;
            else 
                return mid;
        }

        return right;
    }
};

34、在排序数组中查找元素的第一个和最后一个位置

LeetCode:34.在排序数组中查找元素的第一个和最后一个位置

在这里插入图片描述

  • 暴力求解
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* searchRange(int* nums, int numsSize, int target, int* returnSize){
    int i;
    int flag = 1;
    int *ret = (int *)malloc(sizeof(int) * 2);

    ret[0] = -1;
    ret[1] = -1;

    for (i = 0; i < numsSize; i++) {
        if (nums[i] == target && flag == 1) {
            ret[0] = i;
            flag = 0;
        }

        if (nums[i] == target && flag == 0) {
            ret[1] = i;
        }
    }

    *returnSize = 2;

    return ret;
}
  • 二分法:分别找出左右边界
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int getRightBorder(int *nums, int numsSize, int target) {
    int left = 0, right = numsSize - 1;
    int middle = 0;
    int rightBorder = -1;

    while (left <= right) {
        middle = left + ((right - left) >> 1);

        if (nums[middle] == target) {
            rightBorder = middle;
        }

        if (nums[middle] > target) {
            right = middle - 1;
        }else {
            left = middle + 1;
        }
    }

    return rightBorder;
}

int getLeftBorder(int *nums, int numsSize, int target) {
    int left = 0, right = numsSize - 1;
    int middle = 0;
    int leftBorder = -1;

    while (left <= right) {
        middle = left + ((right - left) >> 1);

        if (nums[middle] == target) {
            leftBorder = middle;
        }
        if (nums[middle] < target) {
            left = middle + 1;
        }else {
            right = middle - 1;
        }
    }

    return leftBorder;
}

int* searchRange(int* nums, int numsSize, int target, int* returnSize){
    int *ret = (int *)malloc(sizeof(int) * 2);

    int rightBorder = getRightBorder(nums, numsSize, target);
    int leftBorder = getLeftBorder(nums, numsSize, target);

    if (rightBorder == -1 || leftBorder == -1) {
        ret[0] = -1;
        ret[1] = -1;
    }else {
        ret[0] = leftBorder;
        ret[1] = rightBorder;
    }

    *returnSize = 2;

    return ret;
}

cpp

class Solution {
public:
    int getLeftBorder(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        int mid = 0;
        int leftBorder = -1;

        while (left <= right) {
            mid = left + ((right - left) >> 1);

            if (nums[mid] == target)
                leftBorder = mid;
            
            if (nums[mid] < target)
                left = mid + 1;
            else 
                right = mid - 1;
        }

        return leftBorder;
    }

    int getRightBorder(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        int mid = 0;
        int rightBorder = -1;

        while (left <= right) {
            mid = left + ((right - left) >> 1);

            if (nums[mid] == target){
                rightBorder = mid;
            }
            
            if (nums[mid] > target){
                right = mid - 1;;
            } else {
                left = mid + 1;
            }
        }

        return rightBorder;
    }

    vector<int> searchRange(vector<int>& nums, int target) {
        int leftBorder = getLeftBorder(nums, target);
        int rightBorder = getRightBorder(nums, target);

        if (leftBorder != -1 && rightBorder != -1)
            return vector<int> {leftBorder, rightBorder};
        else 
            return vector<int> {-1, -1};
    }
};

69、x的平方根

LeetCode:69、X的平方根

在这里插入图片描述

  • 暴力求解
int mySqrt(int x){
    // 暴力求解
    int factor = 0;

    for (int i = 0; i <= x; i++) {
        if ((double)i * i <= x) {
            factor = i;
        }else {
            return factor;
        }
    }
    return x;
}
  • 二分法
int mySqrt(int x){
    int left = 0, right = x;
    int middle = 0;
    long temp = 0;
    int factor = 0;

    while (left <= right) {
        middle = left + ((right - left) >> 1);

        temp = (long)middle *middle;
        if (temp <= x) {
            factor = middle;
            left = middle + 1;
        }else {
            right = middle -1;
        }
    }
    return factor;
}

cpp

class Solution {
public:
    int mySqrt(int x) {
        if (0 == x || 1 == x) {
            return x;
        }
        
        int left = 1;
        int right = x / 2;
        int mid = 0;
        long temp = 0.0;
        int factor = 0;

        while (left <= right) {
            mid = left + ((right - left) >> 1);

            temp = (long)mid * mid;

            if (temp <= x) {
                factor = mid;
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return factor;
    }
};

367、有效的完全平方数

LeetCode:367、有效的完全平方数
在这里插入图片描述

  • 暴力求解
bool isPerfectSquare(int num){
    // 暴力解法
    int i;
    for (i = 1; i <= (num / 2 + 1); i++) {
        if ((long)i * i == num) {
            return true;
        }
    }
    return false;
}
  • 二分法
bool isPerfectSquare(int num){
    // 二分法
    int left = 0, right = num;
    int middle = 0;

    while (left <= right) {
        middle = left + ((right - left) >> 1);

        if ((long)middle * middle == num) {
            return true;
        }else if ((long)middle * middle > num){
            right = middle - 1;
        }else {
            left = middle + 1;
        }
    }
    
    return false;
}

cpp

class Solution {
public:
    bool isPerfectSquare(int num) {
        if (1 == num) {
            return true;
        }

        int left = 1;
        int right = num / 2;
        int mid = 0;
        long temp = 0;

        while (left <= right) {
            mid = left + ((right - left) >> 1);
            temp = (long)mid * mid;

            if (temp < num) {
                left = mid + 1;
            } else if (temp > num) {
                right = mid - 1;
            } else {
                return true;
            }
        }

        return false;
    }
};

1.3 移除元素(双指针法)

1.3.1 双指针法介绍

  • 数组元素无法真正移除,只能靠后一个元素覆盖前一个元素,返回移除后的数组没有意义。
  • 双指针法(快慢指针法):通过一个快指针和慢指针在一个for循环内完成两个for循环的工作。
    快指针:寻找新数组的元素,新数组就是不含目标元素的数组。
    慢指针:指向更新新数组下标的位置。

1.3.2 相关题目推荐

27、移除元素

LeetCode:27、移除元素
在这里插入图片描述
在这里插入图片描述

  • 暴力解法
int removeElement(int* nums, int numsSize, int val){
    // 暴力解法 两个for循环
    // 时间复杂度:O(n^2)
    // 空间复杂度:O(1)
    int size = numsSize;
    for (int i = 0; i < size; i++) {
        if (nums[i] == val) { //发现需要移动的元素,就将数组整体向前移动一位
            for (int j = i + 1; j < size; j++) {
                nums[j - 1] = nums[j];
            }
            i--; // 因为i下标以后的元素都向前移动了一位,所以i也向前移动一位
            size--; // 此时数组的大小 -1
        }
    }
    return size;
}
  • 双指针法
int removeElement(int* nums, int numsSize, int val){
    // 通用解法
    // 世界复杂度:O(n)
    // 空间复杂度:O(1)
    int count = 0;
    for (int i = 0; i < numsSize; i++) {
        if (nums[i] != val) {
            nums[count++] = nums[i];
        }
    }
    return count;
}

cpp

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int count = 0;
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] != val) {
                nums[count++] = nums[i];
            }
        }

        return count;
    }
};
  • 双向双指针
int removeElement(int* nums, int numsSize, int val){
    /**
    * 相向双指针方法,基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素
    * 时间复杂度:O(n)
    * 空间复杂度:O(1)
    */
    int left_index = 0;
    int right_index = numsSize - 1;

    while (left_index <= right_index) {
        // 找到左边等于val的元素
        while (left_index <= right_index && nums[left_index] != val) {
            left_index++;
        }
        // 找到右边不等于val地元素
        while (left_index <= right_index && nums[right_index] == val) {
            right_index--;
        }
        // 将右边不等于val的元素覆盖左边等于val的元素
        if (left_index < right_index) {
            nums[left_index++] = nums[right_index--];
        }
    }

    return left_index; // leftIndex一定指向了最终数组末尾的下一个元素
}

cpp

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int left = 0;
        int right = nums.size() - 1;

        while (left <= right) {
            while (left <= right && nums[left] != val) {
                left++;
            }

            while (left <= right && nums[right] == val) {
                right--;
            }

            if (left <= right) {
                nums[left++] = nums[right--];
            }
        }

        return left;
    }
};

26、删除有序数组中的重复项

LeetCode:26、删除有序数组中的重复项
在这里插入图片描述
在这里插入图片描述

  • 双指针法
    (我写的版本)
int removeDuplicates(int* nums, int numsSize){
    int slow = 0;

    for (int i = 0; i < numsSize; i++) {
        if (nums[i] != nums[slow]) {
            nums[++slow] = nums[i];
        }
    }

    return slow + 1;
}

参考版本

int removeDuplicates(int* nums, int numsSize){
    // 双指针法
    // 时间复杂度:O(n)
    // 空间复杂度:O(1)

    if (0 == numsSize) {
        return 0;
    }

    int fast = 1, slow = 1;
    while (fast <numsSize) {
        if (nums[fast] != nums[fast - 1]) {
            nums[slow++] = nums[fast];
        }
        fast++;
    }
    return slow;
}

cpp

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if (nums.size() == 1) {
            return 1;
        }
        
        int slow = 1;
        int fast = 1;
        
        while (fast < nums.size()) {
            if (nums[fast] != nums[fast - 1]) {
                nums[slow++] = nums[fast];
            }

            fast++;
        }

        return slow;
    }
};

283、移动零

在这里插入图片描述

  • 双指针法(覆盖)
void moveZeroes(int* nums, int numsSize){
    // 双指针法(快慢指针)
    int slow = 0;
    for (int fast = 0; fast < numsSize; fast++) {
        if (nums[fast] != 0)
            nums[slow++] = nums[fast];
    }

    // 将slow后面的元素全部赋值为0
    while (slow < numsSize) {
        nums[slow++] = 0;
    }
}

cpp

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int count = 0;
        int i = 0;
        for (i = 0; i < nums.size(); i++) {
            if (nums[i] != 0) {
                nums[count++] = nums[i];
            }
        }

        while (count < nums.size()) {
            nums[count++] = 0;
        }
    }
};
  • 双指针法(交换)
void moveZeroes(int* nums, int numsSize){
    // 双指针法(交换)
    // 时间复杂度:O(n)
    // 空间复杂度:O(1)
    void swap(int *a, int *b) {
        int temp = *a;
        *a = *b;
        *b = temp;
    }

    // 左指针左边均为非零数
    // 右指针左边直到左指针处均为零
    int left = 0, right = 0;
    while (right < numsSize) {
        if (nums[right]) {
            swap(nums + left, nums + right);
            left++;
        }
        right++;
    }
}

cpp

class Solution {
public:
    void swap(int &a, int &b) {
        int temp = a;
        a = b;
        b = temp;
    }

    void moveZeroes(vector<int>& nums) {
        int left = 0;
        int right = 0;

        while (right < nums.size()) {
            if (nums[right] != 0) {
                swap(nums[left], nums[right]);
                left++;
            }

            right++;
        }
    }
};

844、比较含退格的字符串(好难啊!)

在这里插入图片描述

  • 双指针法
bool backspaceCompare(char * s, char * t){
    int i = strlen(s) - 1;
    int j = strlen(t) - 1;
    int skip_s = 0;
    int skip_t = 0;

    while (i >= 0 || j >= 0) {
        // 先找到 s 中第一个需要比较的字符(即去除 # 影响后的第一个待比较字符)
        while (i >= 0) {
            if (s[i] == '#') {
                skip_s++;
                i--;
            }else if (skip_s > 0) {
                skip_s--;
                i--;
            }else {
                break;
            }
        }
        // 再找到 t 中第一个需要比较的字符(即去除 # 影响后的第一个待比较字符)
        while (j >= 0) {
            if (t[j] == '#') {
                skip_t++;
                j--;
            }else if (skip_t > 0) {
                skip_t--;
                j--;
            }else {
                break;
            }
        }

        // 然后开始比较,注意有下面这个 if 条件的原因是:如果 index = 0 位置上为 '#',则 i, j 会为 -1
        // 而 index = -1 的情况应当处理。
        if (i >= 0 && j >= 0) {
            // 如果待比较字符不同,return false
            if (s[i] != t[j]) {
                return false;
            }
    // (i >= 0 && j >= 0) 为 false 情况为
    // 1. i < 0 && j >= 0
    // 2. j < 0 && i >= 0
    // 3. i < 0 && j < 0
    // 其中,第 3 种情况为符合题意情况,因为这种情况下 s 和 t 都是 index = 0 的位置为 '#' 而这种情况下
    // 退格空字符即为空字符,也符合题意,应当返回 True。
    // 但是,情况 1 和 2 不符合题意,因为 s 和 t 其中一个是在 index >= 0 处找到了待比较字符,另一个没有找到
    // 这种情况显然不符合题意,应当返回 False,下式便处理这种情况。
        }else if (i >= 0 || j >= 0) {
            return false;
        }
        i--;
        j--;
    }    
    return true;
}

cpp

class Solution {
public:
    bool backspaceCompare(string s, string t) {
        int i = s.length() - 1;
        int j = t.length() - 1;
        int flag_s = 0;
        int flag_t = 0;

        while (i >= 0 || j >= 0) {
            while (i >= 0) {
                if (s[i] == '#') {
                    flag_s++;
                    i--;
                } else if (flag_s > 0) {
                    flag_s--;
                    i--;
                } else {
                    break;
                }
            }

            while (j >= 0) {
                if (t[j] == '#') {
                    flag_t++;
                    j--;
                } else if (flag_t > 0) {
                    flag_t--;
                    j--;
                } else {
                    break;
                }
            }

            if (i >= 0 && j >= 0) {
                if (s[i] != t[j]) {
                    return false;
                }
            } else if (i >= 0 || j >= 0) {
                return false;
            }
        
            i--;
            j--;
        }    
        
        return true;
    }
};
  • 重构字符串
char *build(char *string) {
    int size = strlen(string);
    int len = 0;
    char *ret = (char *)malloc(sizeof(char) *(size + 1));
    for (int i = 0; i < size; i++) {
        if (string[i] != '#') {
            ret[len++] = string[i];
        }else if (len > 0) {
            len--;
        }
    }
    ret[len] = '\0';
    return ret;
}


bool backspaceCompare(char * s, char * t){
    // 重构字符串
    // 时间复杂度:O(n)
    // 空间复杂度:O(1)
    return strcmp(build(s), build(t)) == 0;
}

cpp

class Solution {
public:
    string getString(const string &S) {
        string s;
        for (int i = 0; i < S.size(); i++) {
            if (S[i] != '#') {
                s += S[i];
            } else if (!s.empty()) {
                s.pop_back();
            }
        }

        return s;
    }

    bool backspaceCompare(string s, string t) {
        return getString(s) == getString(t);
    }
};

1.4 有序数组的平方(双指针法)

977、有序数组的平方

在这里插入图片描述

  • 双指针法
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* sortedSquares(int* nums, int numsSize, int* returnSize){
    // 双指针
    // 时间复杂度:O(n)
    // 空间复杂度:O(1)
    int *arr = (int *)malloc(sizeof(int) * numsSize);
    int left = 0;
    int right = numsSize - 1;
    int k = numsSize - 1;

    while (left <= right) {
        if (nums[left] *nums[left] <= nums[right] * nums[right]) {
            arr[k--] = nums[right] *nums[right];
            right--;
        }else {
            arr[k--] = nums[left] * nums[left];
            left++;
        }
    }

    *returnSize = numsSize;

    return arr;
}

代码中平方对比可以转换一下:

    while (left <= right) {
        // 注意这一步的操作,没有直接比较平方
        if (nums[left] + nums[right] <= 0) {
            arr[k--] = nums[left] *nums[left];
            left++;
        }else {
            arr[k--] = nums[right] * nums[right];
            right--;
        }
    }

cpp

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        vector<int> ret(nums.size(), 0);
        int k = ret.size() - 1;
        
        int left = 0; 
        int right = nums.size() - 1;

        while (left <= right) {
            if (nums[left] + nums[right] < 0) {
                ret[k--] = nums[left] * nums[left];
                left++;
            } else {
                ret[k--] = nums[right] * nums[right];
                right--;
            }
        }

        return  ret;
    }
};

1.5 长度最小的子数组(滑动窗口法)

1.5.1 滑动窗口法介绍

  • 滑动窗口法:不断调节子序列的起始位置和终止位置,从而得到想要的结果(也可以理解为双指针的一种)。
  • 滑动窗口法三点注意:
    (1)窗口内是什么?
    (2)如何移动窗口的起始位置?
    (3)如何移动窗口的结束位置?

1.5.2 相关题目推荐

209、长度最小的子数组

在这里插入图片描述

  • 暴力解法(超出时间限制)
int minSubArrayLen(int target, int* nums, int numsSize){
    int count = INT32_MAX;
    int sum = 0;
    int k = 0;

    for (int i = 0; i < numsSize; i++) {
        sum = 0;
        for (int j = i; j < numsSize; j++) {
            sum += nums[j];
            if (sum >= target) {
                k = j - i + 1;
                count = count < k ? count : k;
                break;
            }
        }
    }

    return count == INT32_MAX ? 0 : count;
}
  • 滑动窗口法
int minSubArrayLen(int target, int* nums, int numsSize){
    // 滑动窗口法
    // 时间复杂度:O(n)
    // 空间复杂度:O(1)
    int count = INT32_MAX;
    int sum = 0;
    int left = 0; // left表示滑动窗口的起始位置,i表示滑动窗口的结束位置

    for (int i = 0; i < numsSize; i++) {
        sum += nums[i];
        // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
        while (sum >= target) {
            count = count < (i - left + 1) ? count : (i - left + 1);
            // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
            sum -= nums[left++];
        }
    }
    // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
    return count == INT32_MAX ? 0 : count;
}

cpp

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int count = INT32_MAX;
        int left = 0;
        int right = 0;
        int sum = 0;

        while (right < nums.size()) {
            sum += nums[right];

            while (sum >= target) {
                count = count < (right - left + 1) ? count : (right - left + 1);
                sum -= nums[left++];
            }

            right++;
        }

        return count == INT32_MAX ? 0 : count;
    }
};

904、水果成篮

在这里插入图片描述
在这里插入图片描述

  • 滑动窗口法
#define MAX  100001

int totalFruit(int* fruits, int fruitsSize){
    int count = 0, kind = 0;
    int array[MAX] = {0}; //存放各种水果出现的次数
    int left = 0, right = 0;
    
    for (; right < fruitsSize; right++) {
        if (array[fruits[right]] == 0) {
            kind++;
        }

        array[fruits[right]]++;

        while (kind > 2) {
            array[fruits[left]]--;
            if (array[fruits[left]] == 0) {
                kind--;
            }

            left++;
        }

        count = count > (right - left + 1) ? count : (right - left + 1);
    }

    return count;
}

cpp

#define Max 100001

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        int n = fruits.size();
        unordered_map<int, int> cnt;

        int left = 0;
        int count = 0;
        for (int right = 0; right < n; right++) {
            cnt[fruits[right]]++;

            while (cnt.size() > 2) {
                auto it = cnt.find(fruits[left]);
                it->second--;

                if (it->second == 0) {
                    cnt.erase(it);
                }

                left++;
            }
            count = max(count, right - left + 1);
        }

        return count;
    }
};

1.6 螺旋矩阵(模拟行为法)

59、螺旋矩阵 II

在这里插入图片描述
在这里插入图片描述

  • 方法一:只适合方阵
int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){
    //初始化返回的结果数组的大小
    *returnSize = n;
    *returnColumnSizes = (int*)malloc(sizeof(int) * n);

    //初始化返回结果数组array
    int **array = (int **)malloc(sizeof(int *) * n);
    for (int i = 0; i < n; i++) {
        array[i] = (int *)malloc(sizeof(int) * n);
        (*returnColumnSizes)[i] = n;
    }

    // 设置每次循环的起始位置
    int startx = 0, starty = 0;
    // 添加的数字
    int count = 1;
    // 偏移数
    int offset = 1;
    // 循环的圈数
    int circle = n/2;

    int i, j;
    while (circle--) {
        // 模拟上侧从左到右
        for (j = starty; j < n - offset; j++) 
            array[startx][j] = count++;
        // 模拟右侧从上到下
        for (i = startx; i < n - offset; i++)
            array[i][j] = count++;
        // 模拟下侧从右到左
        for (; j > starty; j--)
            array[i][j] = count++;
        // 模拟左侧从下到上
        for (; i > startx; i--) {
            array[i][j] = count++;
        }
        // 遍历起始位置加一 
        startx++;
        starty++;
        // 位置偏移加一
        offset++;
    }
    // 若n为奇数需要单独给矩阵中间赋值
    if (n % 2)
        array[n / 2][n / 2] = count;

    return array;
}
  • 方法二:适合任意矩阵
int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){
    //初始化返回的结果数组的大小
    *returnSize = n;
    *returnColumnSizes = (int*)malloc(sizeof(int) * n);

    //初始化返回结果数组array
    int **array = (int **)malloc(sizeof(int *) * n);
    for (int i = 0; i < n; i++) {
        array[i] = (int *)malloc(sizeof(int) * n);
        (*returnColumnSizes)[i] = n;
    }

    int x = 0, y = 0;
    int x_max = n - 1, y_max = n - 1;
    int count = 1;
    
    int i, j;
    while (1) {
        for (j = y; j <= y_max; j++)
            array[x][j] = count++;
        if (++x > x_max) break;

        for (i = x; i <= x_max; i++)
            array[i][y_max] = count++;
        if (--y_max < y) break;

        for (j = y_max; j >= y; j--)
            array[x_max][j] = count++;
        if (--x_max < x) break;

        for (i = x_max; i >= x; i--)
            array[i][y] = count++;
        if (++y > y_max) break;
    }

    return array;
}

cpp

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> ret(n, vector<int>(n));

        int x = 0, y = 0;
        int x_max = n - 1, y_max = n - 1;
        int count = 1;

        while (1) {
            for (int j = y; j <= y_max; j++) 
                ret[x][j] = count++;
            if (++x > x_max) break;

            for (int i = x; i <= x_max; i++) 
                ret[i][y_max] = count++;
            if (--y_max < y) break;

            for (int j = y_max; j >= y; j--)
                ret[x_max][j] = count++;
            if (--x_max < x) break;

            for (int i = x_max; i >= x; i--)
                ret[i][y] = count++;
            if (++y > y_max) break;
        }

        return ret;
    }
};

54、 螺旋矩阵

在这里插入图片描述
在这里插入图片描述

int* spiralOrder(int** matrix, int matrixSize, int* matrixColSize, int* returnSize){
    if (0 == matrixSize) {
        *returnSize = 0;
        return NULL;
    }

    int row = matrixSize, column = matrixColSize[0];
    int size = row * column;
    *returnSize = size;

    int *array = malloc(sizeof(int) * size);

    int x = 0, y = 0;
    int x_max = row - 1, y_max = column - 1;
    int count = 0;

    int i, j;
    while (1) {
        for (j = y; j <= y_max; j++)
            array[count++] = matrix[x][j];
        if (++x > x_max) break;

        for (i = x; i <= x_max; i++)
            array[count++] = matrix[i][y_max];
        if (--y_max < y) break;

        for (j = y_max; j >= y; j--)
            array[count++] = matrix[x_max][j];
        if (--x_max < x) break;

        for (i = x_max; i >= x; i--)
            array[count++] = matrix[i][y];
        if (++y > y_max) break;
    }

    return array;
}

剑指 Offer 29. 顺时针打印矩阵

在这里插入图片描述

int* spiralOrder(int** matrix, int matrixSize, int* matrixColSize, int* returnSize){
    if (0 == matrixSize) {
        *returnSize = 0;
        return NULL;
    }

    int row = matrixSize, column = matrixColSize[0];
    int size = row * column;
    *returnSize = size;

    int *array = malloc(sizeof(int) * size);

    int x = 0, y = 0;
    int x_max = row - 1, y_max = column - 1;
    int count = 0;

    int i, j;
    while (1) {
        for (j = y; j <= y_max; j++)
            array[count++] = matrix[x][j];
        if (++x > x_max) break;

        for (i = x; i <= x_max; i++)
            array[count++] = matrix[i][y_max];
        if (--y_max < y) break;

        for (j = y_max; j >= y; j--)
            array[count++] = matrix[x_max][j];
        if (--x_max < x) break;

        for (i = x_max; i >= x; i--)
            array[count++] = matrix[i][y];
        if (++y > y_max) break;
    }

    return array;
}

总结

通过对数组的回顾,介绍了四种方法:
二分法双指针法滑动窗口法模拟行为法

在这里插入图片描述

参考:《代码随想录》数组篇

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值