【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;
}
};