总结
值得再看的点:
T88 合并两个有序数组 简单模拟 边界条件
// 2024.8.24
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int p1=0, p2=0, p=0;
int ans[205] = {0};
while (p1 < m || p2 < n){
if (p1 >= m || m == 0) {
while (p2 < n) ans[p++] = nums2[p2++];
break;
}
if (p2 >= n || n == 0){
while (p1 < m) ans[p++] = nums1[p1++];
break;
}
if (nums1[p1] <= nums2[p2])
ans[p++] = nums1[p1++];
else
ans[p++] = nums2[p2++];
}
for (int i=0; i<n+m; i++)
nums1[i] = ans[i];
}
};
T27 移除元素
// 2024.8.24
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int p1=0;
int p2=0;
int len = nums.size();
while (p2 < len){
if (nums[p2] != val)
nums[p1++] = nums[p2++];
else p2++;
}
return p1;
}
};
T26&80 删除有序数组的重复项(I & II)
// 2024.8.25
// TI
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int len = nums.size();
int p = 1;
int current_val = nums[0];
int pos = 1;
while (p < len){
if (current_val == nums[p]){ // 放弃这个数
p++;
continue;
}
// 要这个数
current_val = nums[p++];
nums[pos++] = current_val;
}
return pos;
}
};
//TII
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int len = nums.size();
if (len <= 2) return len;
int pos_insert = 2; //前两个不变
int pos_search = 2;
int current_val_st = nums[0] == nums[1]? 0:1;
int current_val = nums[pos_search - 1];
while (pos_search < len){
if (nums[pos_search] == current_val){
if (pos_search - current_val_st >= 2) pos_search++;
else {
nums[pos_insert++] = current_val;
pos_search++;
}
}
else{
current_val = nums[pos_search];
current_val_st = pos_search++;
nums[pos_insert++] = current_val;
}
}
return pos_insert;
}
};
T169 多数元素
// 2024.8.26
class Solution {
public:
int majorityElement(vector<int>& nums) {
int pos = floor(nums.size() / 2);
sort(nums.begin(), nums.end());
return nums[pos];
}
};
vector排序
T189 轮转数组
方法一:暴力模拟,时间复杂度O(n^2)
// 2024.8.26
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int len = nums.size();
while (k--){
int tail = nums[len - 1];
int p = len;
while (--p > 0){
nums[p] = nums[p - 1];
}
nums[0] = tail;
}
}
};
方法二:根据提示观察规律,使用反转数组(也可以不申请新内存空间,空间O(1)实现)
// 2024.8.26
class Solution {
public:
const int maxlen = 1e5 + 1;
void rotate(vector<int>& nums, int k) {
int len = nums.size();
if (len <= 1) return;
k = k % len;
int nums_reverse[maxlen];
for (int i=0; i<len; i++)
nums_reverse[i] = nums[len-i-1];
int left, right, tmp;
left = 0;
right = k - 1;
while (left <= right){
nums[left] = nums_reverse[right];
nums[right] = nums_reverse[left];
left++;
right--;
}
left = k;
right = len - 1;
while (left <= right){
nums[left] = nums_reverse[right];
nums[right] = nums_reverse[left];
left++;
right--;
}
}
};
8.27:
T121&122 买卖股票的最佳时机(I & II)
T121:
方法一:暴力枚举买入和卖出的天数,时间复杂度O(n^2)
class Solution {
public:
int maxProfit(vector<int>& prices) {
int tot_Days = prices.size(); // 总天数
int max_prof = 0;
for (int buy_day = 0; buy_day < tot_Days - 1; buy_day++){
for (int sell_day = buy_day + 1; sell_day < tot_Days; sell_day++){
max_prof = max(max_prof, prices[sell_day] - prices[buy_day]);
}
}
return max_prof;
}
};
方法二:空间换时间,记录截至当前天数的最低买入花费,以及在这之后卖出的最高收获
class Solution {
public:
const int maxlen = 1e5 + 5;
int maxProfit(vector<int>& prices) {
int tot_Days = prices.size(); // 总天数
if (tot_Days <= 1) return 0;
int max_prof = 0;
int min_before[maxlen]; // 在这一天之前(不含)买入的最低价
int max_after[maxlen]; // 在这一天之后(含)卖出的最高价
int p;
min_before[1] = prices[0];
p = 2;
while (p < tot_Days){
min_before[p] = min(prices[p - 1], min_before[p - 1]);
p++;
}
p = tot_Days - 2;
max_after[tot_Days - 1] = prices[tot_Days - 1];
while (p > 0){
max_after[p] = max(max_after[p + 1], prices[p]);
p--;
}
int n = 1;
for (int i = 1;i < tot_Days; i++)
max_prof = max(max_prof, max_after[i] - min_before[i]);
return max_prof;
}
};
方法二补充:可以使用空间复杂度O(1)的解法,遍历一遍,只用一个变量维护目前为止的最低买入价格就好了。(官方题解)
T122:
dp,可以用滚动数组省内存
class Solution {
public:
const int maxn = 3e4+5;
int maxProfit(vector<int>& prices) {
int len = prices.size();
int f[maxn][2];
f[0][0] = 0;
f[0][1] = -prices[0];
for (int i = 1; i < len; i++){
f[i][0] = max(f[i-1][0], f[i-1][1] + prices[i]);
f[i][1] = max(f[i-1][1], f[i-1][0] - prices[i]);
}
return f[len-1][0];
}
};
题解中贪心的方法...
T134 加油站(思路、贪心)
//2024.9.1
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int st = 0;
int n = gas.size();
while (st < n){
while (st < n && gas[st] - cost[st] < 0)
st++;
if (st < n){
// 开始判断这个点作为起点可不可行
int current_id = st;
int next_id = st==n-1? 0 : st + 1;
int num = 1; // 经过了几站
int val = gas[current_id] - cost[current_id];
while (num < n){
current_id = next_id;
next_id = current_id == n - 1? 0 : current_id + 1;
val += gas[current_id] - cost[current_id];
if (val < 0) break;
num++;
}
if (num < n)
st+= num;
else
return st;
}
}
return -1;
}
};
T135 分发糖果
感觉只能多试几个样例才能get到需要正反遍历
// 2024.9.3
class Solution {
public:
int candy(vector<int>& ratings) {
int sum = 0;
int n = ratings.size();
vector<int> cnt(n, 1);
// 正向遍历
for (int i = 1; i < n; i++){
if (ratings[i] > ratings[i - 1]){
cnt[i] = cnt[i - 1] + 1; //相邻高的要得到更多
}
}
// 反向遍历
for (int i = n - 2; i >= 0; i--){
if (ratings[i] > ratings[i + 1]){
cnt[i] = max(cnt[i + 1] + 1, cnt[i]);
// cout << cnt[i] << endl;
}
}
for (int i = 0; i < n; i++)
sum+= cnt[i];
return sum;
}
};
T42 接雨水
也是一道思路需要多试样例才能想清楚的。画图有用。
// 2024.09.03
class Solution {
public:
int trap(vector<int>& height) {
// 根据题解:每个点储存的雨水 取决于 左右的各自最大值
int n = height.size();
if (n <= 2) return 0;
int left_max[n + 5];
memset(left_max, -1, sizeof(left_max));// 记录当前位置左边最高值
int sum = 0;
left_max[0] = -1;
for (int i = 1; i < n; i++){
int tmp = max(left_max[i-1], height[i-1]);
left_max[i] = tmp;
}
int right_max = height[n-1]; // 当前位置右边最高值
for (int i = n-2; i >=0; i--){
int tmp = min(left_max[i], right_max) - height[i];
if (tmp > 0) sum += tmp;
right_max = max(right_max, height[i]);
}
return sum;
}
};
T28 找出字符串中第一个匹配项的下标
从这道题了解KMP字符串匹配算法。
参考链接:
再写一遍
T68 文本左右对齐
耐心写的模拟题
//2024.9.6
class Solution {
public:
vector<string> fullJustify(vector<string>& words, int maxWidth) {
int tot = words.size();
string current_line = "";
int current_len = 0;
int st = 0;//记录每一行起始单词的下标
vector<string> ans;
for (int i=0; i<tot; i++){
if (current_len == 0){ // 一行的开头
current_len += words[i].length();
st = i;
}
else {
if (current_len + 1 + words[i].length() <= maxWidth){
current_len += 1 + words[i].length();
}
else{ // 当前这一行已经满了,处理这一行的输出
int word_len = 0;
int word_num = i - st; // (i-1)-(st)+1
for (int j = st; j <= i - 1; j ++)
word_len += words[j].length();
int blank_num = maxWidth - word_len; // 这一行中的空格数
if (word_num == 1){
ans.insert(ans.end(),words[st] + string(blank_num, ' '));
}
else{
int blank_base = blank_num / (word_num - 1);
int blank_res = blank_num % (word_num - 1);
string line="";
for (int j = st; j < i - 1; j++){
line += words[j] + string(blank_base, ' ');
if (blank_res) {
line += " ";
blank_res--;
}
}
line += words[i - 1];
ans.insert(ans.end(), line);
}
// 把当前的这个单词作为新一行的起点
current_len = words[i].length();
st = i;
}
}
}
if (current_len){
string line = "";
for (int j = st; j < tot - 1; j++){
line += words[j] + " ";
}
line += words[tot - 1];
while (line.length() < maxWidth) line+=" ";
ans.insert(ans.end(), line);
}
return ans;
}
};