算法题

102 阅读2分钟
数组
  1. 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

    双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

    class Solution {
    public:
        int removeElement(vector<int>& nums, int val) {
            int slowIndex = 0;
            for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
                if (val != nums[fastIndex]) {
                    nums[slowIndex++] = nums[fastIndex];
                }
            }
            return slowIndex;
        }
    };
    
  2. 给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

    滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果

    class Solution {
    ​
        // 滑动窗口
        public int minSubArrayLen(int s, int[] nums) {
            int left = 0;
            int sum = 0;
            int result = Integer.MAX_VALUE;
            for (int right = 0; right < nums.length; right++) {
                sum += nums[right];
                while (sum >= s) {
                    result = Math.min(result, right - left + 1);
                    sum -= nums[left++];
                }
            }
            return result == Integer.MAX_VALUE ? 0 : result;
        }
    }
    
  3. 给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

    Solution {
    public:
        vector<vector<int>> generateMatrix(int n) {
            vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
            int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
            int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
            int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
            int count = 1; // 用来给矩阵中每一个空格赋值
            int offset = 1; // 每一圈循环,需要控制每一条边遍历的长度
            int i,j;
            while (loop --) {
                i = startx;
                j = starty;
    ​
                // 下面开始的四个for就是模拟转了一圈
                // 模拟填充上行从左到右(左闭右开)
                for (j = starty; j < starty + n - offset; j++) {
                    res[startx][j] = count++;
                }
                // 模拟填充右列从上到下(左闭右开)
                for (i = startx; i < startx + n - offset; i++) {
                    res[i][j] = count++;
                }
                // 模拟填充下行从右到左(左闭右开)
                for (; j > starty; j--) {
                    res[i][j] = count++;
                }
                // 模拟填充左列从下到上(左闭右开)
                for (; i > startx; i--) {
                    res[i][j] = count++;
                }
    ​
                // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
                startx++;
                starty++;
    ​
                // offset 控制每一圈里每一条边遍历的长度
                offset += 2;
            }
    ​
            // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
            if (n % 2) {
                res[mid][mid] = count;
            }
            return res;
    
链表
  1. 反转一个单链表。

    双指针法写出来之后,理解如下递归写法就不难了,代码逻辑都是一样的。

    class Solution {
    public:
        ListNode* reverseList(ListNode* head) {
            ListNode* temp; // 保存cur的下一个节点
            ListNode* cur = head;
            ListNode* pre = NULL;
            while(cur) {
                temp = cur->next;  // 保存一下 cur的下一个节点,因为接下来要改变cur->next
                cur->next = pre; // 翻转操作
                // 更新pre 和 cur指针
                pre = cur;
                cur = temp;
            }
            return pre;
        }
    };