,## 27.移除元素
双指针法
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int n = nums.size();
int left = 0;
for(int right = 0; right < n; right++) {
if(nums[right] != val) {
nums[left] = nums[right];
left++;
}
}
return left;
}
};
优化
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int left = 0, right = nums.size();
while (left < right) {
if (nums[left] == val) {
nums[left] = nums[right - 1];
right--;
} else {
left++;
}
}
return left;
}
};
普通方法
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
// 就是简单筛选
vector<int> result;
int num = 0;
for(int i=0 ; i< nums.size() ; i++) {
if(nums[i] != val) {
result.push_back(nums[i]);
num++;
}
}
// 剩下的
for(int i =0; i< nums.size() - num; i++) {
result.push_back(val);
}
nums = result;
return num;
}
};
121 买卖股票的最佳时机
思路
每次遍历, 算出,如果是最低底价买入,收益如何?? 并且记录一下最低价
class Solution {
public:
int maxProfit(vector<int>& prices) {
int inf = 1e9;
int minprice = inf;
int maxprofit = 0;
for(auto price : prices) {
maxprofit = max(maxprofit , price-minprice);
minprice = min(minprice, price);
}
return maxprofit ;
}
};
169多数元素
我写的答辩code
排序 + 遍历 + 每次判断
class Solution {
public:
int majorityElement(vector<int>& nums) {
int nums_size = nums.size();
// 排序遍历
int sum = 1;
int index = 0; // 下标
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size()-1; i++) {
if(nums[i] == nums[i+1]) {
sum++; // 总数
if(sum > nums_size/2) {
return nums[i];
}
} else {
if(sum > nums_size/2) {
return nums[i];
} else {
sum =1;
}
}
}
return nums[0];
}
};
投票法
class Solution {
public:
int majorityElement(vector<int> &nums) {
int candidate = 0; // 候选数字
int count = 0;
for (int num : nums) {
if (count == 0) {
candidate = num;
}
count += (candidate == num) ? 1 : -1;
}
return candidate;
}
};
数学
class Solution {
public:
int majorityElement(vector<int>& nums) {
sort(nums.begin(), nums.end());
return nums[nums.size() / 2];
}
};
122. 买卖股票的最佳时机II
我的思路
只要后天一天比前一天大, 我就可以赚, 然后累加就好
class Solution {
public:
int maxProfit(vector<int>& prices) {
// 可以理解成有一个数字
// 1 5 3 6
int prices_size = prices.size();
if(prices_size == 1) {
return 0;
}
// 下面
int profit = 0;
for(int i = 1; i< prices_size; i++) {
if(prices[i] > prices[i-1]) {
int Difference= prices[i]-prices[i-1];
profit += Difference;
}
}
return profit;
}
};
```![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/fef3e4e4eb11474a92b3183f2b532285.png)
**官方贪心**
```c++
class Solution {
public:
int maxProfit(vector<int>& prices) {
int ans = 0;
int n = prices.size();
for (int i = 1; i < n; ++i) {
ans += max(0, prices[i] - prices[i - 1]);
}
return ans;
}
};
动态规划
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
int dp[n][2];
dp[0][0] = 0, dp[0][1] = -prices[0];
for (int i = 1; i < n; ++i) {
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
}
return dp[n - 1][0];
}
};
55. 跳跃游戏
题解
class Solution {
public:
bool canJump(vector<int>& nums) {
int k = 0;
for (int i = 0; i < nums.size(); i++) {
// i 表示下标 k 表示最大的位移距离
if (i > k) return false;
k = max(k, i + nums[i]);
}
return true;
}
};
H指数
倒序+遍历判断
这里最重要的是 k 的判断
class Solution {
public:
int hIndex(vector<int>& citations) {
int hIndex_size = citations.size();
int k = 0;
// 排序
sort(citations.begin(),citations.end());
for(int i = hIndex_size-1; i>=0 ; i--) {
if(citations[i] && citations[i] > k) {
k++;
}
}
return k;
}
};
统计所有的次数
class Solution {
public:
int hIndex(vector<int>& citations) {
int n = citations.size(), tot = 0;
vector<int> counter(n + 1);
for (int i = 0; i < n; i++) {
if (citations[i] >= n) {
counter[n]++;
} else {
counter[citations[i]]++;
}
}
for (int i = n; i >= 0; i--) {
tot += counter[i];
if (tot >= i) {
return i;
}
}
return 0;
}
};
跳跃游戏II
class Solution {
public:
int jump(vector<int>& nums) {
// 跳到最后一个元素最少的次数
int start = 0;
int end = 1;
int ans = 0; // 次数
while(end < nums.size()) {
int maxPos = 0; // 每一次都初始化一下最大的距离
for(int i = start; i< end; i++) {
maxPos = max(maxPos, i+nums[i]);
}
// 更新 start end
start = end;
end = maxPos+1;
ans++;
}
return ans;
}
};
轮回数组
太妙了,如果纯简单模拟的话,会有很多问题
就比如, 长度只有1 ,然后k值为3
简单模拟是不可行的
class Solution {
public:
void rotate(vector<int>& nums, int k) {
// 这里本质就一个循环
int n = nums.size(); // 长度
vector<int> result(n);
for(int i = 0; i< n; i++) {
result[(i+k)%n] = nums[i];
}
// 拷贝到原来的数组
nums.assign(result.begin(),result.end());
}
};
除自身以外的的乘积
暴力 超时
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
// 输出answer 输出是 num[i] 除 num[i] 之外元素的乘积
int sum = 1;
int n = nums.size();
vector<int> result(n);
for(int i = 0; i< n; i++) {
for(int j = 0; j <n; j++) {
if(i != j) {
sum *= nums[j];
}
}
result[i] = sum;
sum = 1;
}
return result;
}
};
分类讨论 + 使用除法
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
// 输出answer 输出是 num[i] 除 num[i] 之外元素的乘积
int sum = 1;
int sum2 = 1;
int n = nums.size();
int count = 0; // 记录0的数量
// 下面进行优化
for(int i = 0; i< n; i++) {
if(nums[i] == 0) {
count++;
}
sum*=nums[i];
if(nums[i] != 0) {
sum2*=nums[i];
}
}
// 分情况
if(sum == 0) {
if(count > 1) {
for(int i = 0; i< n; i++) {
nums[i] = 0;
}
} else {
for(int i = 0; i< n; i++) {
if(nums[i] == 0) {
nums[i] = sum2;
} else {
nums[i] = 0;
}
}
}
} else {
for(int i = 0; i< n; i++) {
nums[i] = sum / nums[i];
}
}
return nums;
}
};
使用两个数组建立每一个下标左右两边的乘积
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int length = nums.size();
// L 和 R 分别表示左右两侧的乘积列表
vector<int> L(length, 0), R(length, 0);
vector<int> answer(length);
// L[i] 为索引 i 左侧所有元素的乘积
// 对于索引为 '0' 的元素,因为左侧没有元素,所以 L[0] = 1
L[0] = 1;
for (int i = 1; i < length; i++) {
L[i] = nums[i - 1] * L[i - 1];
}
// R[i] 为索引 i 右侧所有元素的乘积
// 对于索引为 'length-1' 的元素,因为右侧没有元素,所以 R[length-1] = 1
R[length - 1] = 1;
for (int i = length - 2; i >= 0; i--) {
R[i] = nums[i + 1] * R[i + 1];
}
// 对于索引 i,除 nums[i] 之外其余各元素的乘积就是左侧所有元素的乘积乘以右侧所有元素的乘积
for (int i = 0; i < length; i++) {
answer[i] = L[i] * R[i];
}
return answer;
}
};
加油站
下面这种方案无法实现,我本来是想找到差值最大的点,然后开始验证,32/42
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
// 找出差值最大的下标
int n = gas.size();
int max_index = 0;
int max = INT_MIN;
for(int i = 0; i< n; i++) {
int num = gas[i] - cost[i];
if(num > max) {
max = num;
max_index = i;
}
}
int gas_sum = 0;
// 找出最大下标 开始验证
for(int i= max_index; ;) {
gas_sum = gas_sum + gas[i] - cost[i];
if(gas_sum <0) {
return -1;
}
i = (i+1)%n; // 循环
if(i == max_index ) {
break;
}
}
return max_index;
}
};
贪心
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int n = gas.length;
int sum = 0;
int min = 0;
int idx = 0;
for (int i = 0; i < n; i++) {
sum += gas[i] - cost[i];
if (sum < min) {
min = sum;
idx = i + 1;
}
}
return sum < 0 ? -1 : idx;
}
}
罗马数字转整数
重点
这里使用一个 unorder_map 进行记录 键-值 关系
class Solution {
public:
int romanToInt(string s) {
// 特殊情况
unordered_map<char,int> symbolValues = {
{'I', 1},
{'V', 5},
{'X', 10},
{'L', 50},
{'C', 100},
{'D', 500},
{'M', 1000},
};
// 下面进行遍历,然后输出
int result = 0;
for(int i = 0; i< s.size(); i++) {
int value = symbolValues[s[i]];
if(i < s.size()-1 && value < symbolValues[s[i+1]]) {
result -= value;
} else {
result += value;
}
}
return result;
}
};
6. Z字形变换
题解
这里可以这样理解
遍历原来的字符串
然后观察 Z 形 可以发现
就按照列进行放置
然后如果是 第一行 就 往下面走 也就是 +1
如果到了最后一行( numRows -1) 往上走 也就是 -1
知道到达第一行 ( i == 0)
class Solution {
public:
string convert(string s, int numRows) {
if(numRows <2) {
return s;
}
vector<string> rows(numRows);
int i = 0; int flag = -1;
for(char c:s ) {
rows[i].push_back(c);
if(i ==0 || i == numRows-1) {
flag = -flag;
}
i += flag;
}
string res;
for(const string &row : rows ) {
res += row;
}
return res;
}
};
13.
模拟
class Solution {
public:
// 表示 数字 和 罗马数字
string intToRoman(int num) {
const pair<int, string> valueSymbols[] = {
{1000, "M"},
{900, "CM"},
{500, "D"},
{400, "CD"},
{100, "C"},
{90, "XC"},
{50, "L"},
{40, "XL"},
{10, "X"},
{9, "IX"},
{5, "V"},
{4, "IV"},
{1, "I"},
};
string roman;
for(const auto &[value, symbol] : valueSymbols) {
while(num >= value) {
num -= value;
roman += symbol;
}
if(num == 0) {
break;
}
}
return roman;
}
};
补充:
当然可以。范围基于的for循环是一种非常实用的语法,它允许你遍历容器中的所有元素,而无需手动管理迭代器或索引。以下是一些使用这种语法的例子:
1. 遍历数组
假设我们有一个整数数组,我们想要打印出每个元素:
int numbers[] = {1, 2, 3, 4, 5};
for (int num : numbers) {
cout << num << " ";
}
// 输出: 1 2 3 4 5
2. 遍历std::vector
对于std::vector
,范围基于的for循环同样适用:
#include <vector>
std::vector<string> fruits = {"apple", "banana", "cherry"};
for (const auto &fruit : fruits) {
cout << fruit << " ";
}
// 输出: apple banana cherry
3. 遍历std::map
如果你有一个std::map
,你可以遍历它的键值对:
#include <map>
std::map<int, std::string> ageMap = {{1, "Alice"}, {2, "Bob"}, {3, "Charlie"}};
for (const auto &pair : ageMap) {
cout << "Key: " << pair.first << ", Value: " << pair.second << endl;
}
// 输出:
// Key: 1, Value: Alice
// Key: 2, Value: Bob
// Key: 3, Value: Charlie
4. 遍历std::pair
对于std::pair
,你可以使用解构来分别获取两个元素:
std::pair<int, std::string> person(1, "John");
for (const auto &[key, value] : std::initializer_list<std::pair<int, std::string>>{{person}}) {
cout << "Key: " << key << ", Value: " << value << endl;
}
// 输出: Key: 1, Value: John
5. 遍历字符串
字符串也可以使用范围基于的for循环遍历:
std::string greeting = "Hello";
for (char c : greeting) {
cout << c << " ";
}
// 输出: H e l l o
这些例子展示了范围基于的for循环在不同容器和数据结构中的使用方式。通过使用这种语法,你可以写出更简洁、更易于理解的代码。