一、数组
1.删除排序数组中的重复项(双指针):
(1)审题不清,效率不高
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
auto it = nums.begin();
while (it != nums.end() - 1)
{
if (*it == *(it + 1))
{
it = nums.erase(it);
}
else
{
++it;
}
}
return nums.size();
}
};
(2)
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if (nums.empty())return 0;
int left = 0;
for (int right = 1; right < nums.size(); ++right)
{
if (nums[left] != nums[right])
{
nums[++left] = nums[right];
}
}
return ++left;
}
};
2.买卖股票的最佳时机II
(1)贪心算法
因为没有限制买卖的次数,所以我们可以理解为相邻两天的利润和
class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.empty() || prices.size() == 1)return 0;
int profit = 0;
for (int i = 1; i < prices.size(); ++i)
{
if (prices[i] > prices[i - 1])
{
profit += (prices[i] - prices[i - 1]);
}
}
return profit;
}
};
(2)动态规划
定义一个二维数组dp表示这一天结束后的最大利润,dp[i][0]表示这一天结束手中没有股票,这可能是前一天结束后手中就没有股票,或者这一天结束后股票已经卖出;dp[i][1]表示这一天结束手中有股票,这也可能是前一天结束后手中的股票,今天没有购入,或者昨天结束后没有股票,今天买入了。
最后,如果要获得最大利润那就说明最后一天结束后手中是没有股票的。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
vector<vector<int>>dp(len, vector<int>(2, 0));
dp[0][0] = 0;
dp[0][1] = -prices[0];
for (int i = 1; i < len; ++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[len - 1][0];
}
};
3.旋转数组
(1)使用临时数组
class Solution {
public:
void rotate(vector<int>& nums, int k) {
auto temp = nums;
int len = nums.size();
for (int i = 0; i < len; ++i)
{
nums[(i + k) % len] = temp[i];
}
}
};
(2)翻转法
第一步先翻转所有元素
第二步翻转前k个元素
第三步翻转后面的元素
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int len = nums.size();
k %= len;
reverse(nums, 0, len - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, len - 1);
}
void reverse(vector<int>v, int start, int end)
{
while (start < end)
{
auto temp = v[start];
v[start++] = v[end];
v[end--] = temp;
}
}
};
4.存在重复元素
(1)使用了算法sort对数组进行排序,然后在比较相邻的两个元素
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
sort(nums.begin(), nums.end());
for (int i = 1; i < nums.size(); ++i)
{
if (nums[i] == nums[i - 1])
{
return true;
}
}
return false;
}
};
(2)使用set容器
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
set<int>un;
for (auto m : nums)
{
if (un.find(m) != un.cend())
{
return true;
}
un.insert(m);
}
return false;
}
};
5.只出现一次的数字
(1)使用位运算
使用异或运算,将所有值进行异或
异或运算,相异为真,相同为假,所以 a^a = 0 ;0^a = a
因为异或运算 满足交换律 a^b^a = a^a^b = b 所以数组经过异或运算,单独的值就剩下了
class Solution {
public:
int singleNumber(vector<int>& nums) {
int temp = 0;
for (auto n : nums)
{
temp = temp ^ n;
}
return temp;
}
};
6.两个数组的交集II
(1)双指针
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
int i = 0, j = 0;
vector<int>temp;
while (i < nums1.size() && j < nums2.size())
{
if (nums1[i] > nums2[j])
{
++j;
}
else if (nums1[i] < nums2[j])
{
++i;
}
else
{
temp.push_back(nums1[i]);
++i;
++j;
}
}
return temp;
}
};
(2)利用map计数
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
if (nums1.size() > nums2.size())return intersect(nums2, nums1);
map<int, int>m;
vector<int>temp;
for (auto n : nums1)m[n]++;
for (auto n : nums2)
{
if (m.count(n))
{
m[n]--;
temp.push_back(n);
if (m[n] == 0)
{
m.erase(n);
}
}
}
return temp;
}
};
7.加一
判断每一位是否为9,如果不为9直接加1;
class Solution {
public:
vector<int> plusOne(vector<int>& digits) {
int len = digits.size();
for (int i = len - 1; i >= 0; --i)
{
if (digits[i] != 9)
{
digits[i]++;
return digits;
}
else
digits[i] = 0;
}
digits.insert(digits.begin(), 1);
return digits;
}
};
8.移动零
(1)双指针
把非0的往前挪
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int index = 0, i = 0;
for (; i < nums.size(); i++)
{
if (nums[i] != 0)
{
nums[index++] = nums[i];
}
}
while (index < nums.size())
{
nums[index++] = 0;
}
}
};
(2)双指针
交换
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int index = 0, i = 0;
while (i < nums.size())
{
if (nums[i])
{
swap(nums[index], nums[i]);
index++;
}
i++;
}
}
};
9.两数之和
(1)暴力for循环
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int len = nums.size();
for (int i = 0; i < len - 1; i++)
{
for (int j = i + 1; j < len; j++)
{
if (nums[i] + nums[j] == target)
{
return {i, j};
}
}
}
return {};
}
};
(2)哈希表
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int>hashtable;
for (int i = 0; i < nums.size(); ++i)
{
auto it = hashtable.find(target - nums[i]);
if (it != hashtable.end())
{
return { it->second,i };
}
hashtable.insert(make_pair(nums[i],i));
}
return {};
}
};
10.有效的数独
创建两个二维数组和一个三维数组表示行、列和3x3区域数字的出现次数,并初始化。
遍历整个表格。
class Solution {
public:
bool isValidSudoku(vector<vector<char>>& board) {
int row[9][9];
int column[9][9];
int cell[3][3][9];
memset(row, 0, sizeof(row));
memset(column, 0, sizeof(column));
memset(cell, 0, sizeof(cell));
for (int i = 0; i < 9; ++i)
{
for (int j = 0; j < 9; ++j)
{
if (board[i][j] != '.')
{
int num = board[i][j] - '1';
row[i][num]++;
column[j][num]++;
cell[i / 3][j / 3][num]++;
if (row[i][num] > 1 || column[j][num] > 1 || cell[i / 3][j / 3][num] > 1)
return false;
}
}
}
return true;
}
};
11.旋转图像
(1)用翻转代替旋转
首先上下翻转再关于对角线翻转
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for (int i = 0; i < n / 2; ++i)
{
for (int j = 0; j < n; ++j)
{
swap(matrix[i][j], matrix[n - i - 1][j]);
}
}
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < i; ++j)
{
swap(matrix[i][j], matrix[j][i]);
}
}
}
};
(2)直接交换
因为是对称的,所以只要旋转前半部分就可以了
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int len = matrix.size();
for (int i = 0; i < len / 2; i++)
{
for (int j = i; j < len - i - 1; ++j)
{
int m = len - i - 1;
int n = len - j - 1;
auto temp = matrix[i][j];
matrix[i][j] = matrix[n][i];
matrix[n][i] = matrix[m][n];
matrix[m][n] = matrix[j][m];
matrix[j][m] = temp;
}
}
}
};