【LeetCode】Array Topic总结

【LeetCode】717. 1-bit and 2-bit Characters

/*基本思路就是1位1位往后探测,看当前位置往前的所有位是否能够组成满足要求的字符串
因为最后一位是0,所以只要判断前n-1位能否组成满足要求的字符串即可*/
class Solution {
public:
    bool isOneBitCharacter(vector<int>& bits) {
        auto len = bits.size();
        if (len == 1) return true;
        vector<bool> vb(len, false); // vb记录当前位置及之前的位能够组成字符串
        // 为vb[0]和vb[1]赋初值,简单分析一下就知道取值情况
        vb[0] = 1 - bits[0];
        if (bits[1] == 0) vb[1] = true;
        else vb[1] = bits[0];

        for (int i = 2; i < len; ++i) {
            if (bits[i]) { // 当前位是1,则前一位必须也为1,同时前i-2位能组成字符串
                vb[i] = (bits[i-1] == 1) && vb[i-2];
            } else { // 当前位是0,则前一位为1,同时前i-2位能组成字符串,或者前i-1位能组成字符串
                vb[i] = vb[i-1] || ((bits[i-1] == 1) && vb[i-2]);
            }
        }
        // 判断前n-1个位能够组成字符串,即为我们的答案
        return vb[len-2];
    }
};

【LeetCode】 695. Max Area of Island

/*递归。只要找到1的位置,就进行深搜,找到所有相邻的1,同时记录1的个数,即为岛的大小*/
class Solution {
public:
    // x,y是1的位置,res记录1的个数,r,c为grid的行数和列数
    void depth(vector<vector<int>>& grid, int x, int y, int &res, const int& r, const int& c) {
        ++res; // 记录1的个数
        grid[x][y] = 0; // 标记访问,将当前位置清0
        if (x-1 >= 0 && grid[x-1][y] == 1) depth(grid, x-1, y, res, r, c);
        if (x+1 < r  && grid[x+1][y] == 1) depth(grid, x+1, y, res, r, c);
        if (y-1 >= 0 && grid[x][y-1] == 1) depth(grid, x, y-1, res, r, c);
        if (y+1 < c  && grid[x][y+1] == 1) depth(grid, x, y+1, res, r, c);
    }

    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int r = grid.size();
        if (r == 0) return 0;
        int c = grid[0].size();
        int maxres = 0;
        for (int i = 0; i < r; ++i) {
            for (int j = 0; j < c; ++j) {
                if (grid[i][j]) { // 找到一个1,进行深搜
                    int t = 0;
                    depth(grid, i, j, t, r, c);
                    if (t > maxres) maxres = t; // 更新最大值
                }
            }
        }
        return maxres;
    }
};

【LeetCode】667. Beautiful Arrangement II

/*题目让构造一个1到n的排列,且相邻两个数差的绝对值正在能够取遍1到k。
考虑如果前k+1个数正好能组成满足要求的排列,后面的数按顺序排列就好,因为他们的差绝对值为1。
考虑这样一个排列,1,k+1,2,k,3,k-1,...,则差得绝对值正好为k,k-1,k-2,k-3,k-4,
即使用前1到k+1就能够构造出满足要求的排列*/
class Solution {
public:
    vector<int> constructArray(int n, int k) {
        vector<int> res;
        for (int i = 1; i <= k + 1; ++i) {
            // 接下面两行判断什么时候结束构造
            if (i == k + 2 - i) { res.push_back(i); break; }
            if (i > k + 1 - i) break;
            res.push_back(i);
            res.push_back(k + 2 - i);
        }
        // 剩下的数按顺序排列就好
        for (int i = k + 2; i <= n; ++i) res.push_back(i);
        return res;
    }
};

【LeetCode】560. Subarray Sum Equals K

/*一个方法是使用前缀和每个位置之前所有数的和,然后再遍历每个区间,前缀和相减得到区间和,
判断是够等于k,但这个方法的时间复杂度为O(n*n),太高了。
根据前面做题的经验,关于求和的问题,通常会固定一个值,然后找另一个值。应用到本题,就是固定一个前缀和,找到与其相差k的另一个前缀和,具体看代码*/
class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        // 特殊情况处理,本题其实不需要
        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return (nums[0] == k) ? 1 : 0;
        // 使用map帮助查找
        unordered_map<long long, int> m;
        int sumx = 0; // 记录前缀和
        int res = 0;
        ++m[0]; // 考虑区间是从第一个数开始的情况

        for (int i = 0; i < nums.size(); ++i) {
            sumx += nums[i];   // 记录区间和
            res += m[sumx-k];  // 找到前面出现过的和为sumx-k的次数
            ++m[sumx];         // 更新map
        }
        return res;
    } 
};

【LeetCode】169. Majority Element

/*让找出出现次数超过n/2的数。考虑如果存在这样的数,则它与其他数抵消之后,最后数组中肯定只剩它自己,据此有以下代码*/
**class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int cnt = 0; // 当前数有几个
        int res = nums[0];
        for (auto x : nums) {
            if (cnt == 0) { // 说明之前的数都抵消掉了
                res = x; // 记录一个新数
                ++cnt;
            } else {
                if (x == res) ++cnt; // 更新当前数的次数
                else --cnt;      // 抵消掉
            }
        }
        return res;
    }
};

【LeetCode】53. Maximum Subarray

/* 动态规划问题,考虑dp[n]表示以第n个数为结尾的最大和,则dp[n+1]只有两种选择,要么=dp[n]+a[n+1],要么=a[n+1],即=max(dp[n]+a[n+1], a[n+1]),空间复杂度和时间负责度都为O(n),空间复杂度可以优化到O(1) */
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int sumx = 0; // sumx记录以当前数为结尾的最大和
        if (nums.size() == 0) return 0;
        int maxsum = nums[0];
        for (int x : nums) {
            sumx = max(sumx + x, x); // 更新,只与前一个状态的最大和有关
            if (sumx > maxsum) maxsum = sumx;
        }
        return maxsum;
    }
};

【LeetCode】611. Valid Triangle Number

/* 首先进行排序,然后选择一条最大边,只要剩下两条边的和比最大边大就能组成三角形,由于已经有序,查找起来很方便 */
class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        if (nums.size() < 3) return 0;
        sort(nums.begin(), nums.end()); // 排序
        int res = 0;
        int n = nums.size();
        for (int i = n-1; i >= 0; --i) {
            int j = 0, k = i - 1; // 最大边位置i,剩下两条位置为j和k
            while (j < k) {
                // 两边之和太小,只能增加最短边
                if (nums[j] + nums[k] <= nums[i]) ++j; 
                // j满足要求,则j到k-1的所有边,都能和k和i两条边组成三角形,即找到了所有中间边为nums[k]的情况
                // 然后考虑中间边为nums[k-1]的情况,而j无需更新,
                else res += (k-j), --k;
            }
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值