26、删除排序数组中的重复项
给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
//双指针
int removeDuplicates(vector<int>& nums) {
int i = 0;
for (int j = 1; j < nums.size(); j++) {
if (nums[i] != nums[j]) nums[++i] = nums[j];
}
return ++i;
}
122、买卖股票的最佳时机
给定一个数组 prices ,其中 prices[i] 表示股票第 i 天的价格。
在每一天,你可能会决定购买和/或出售股票。你在任何时候 最多 只能持有一股股票。你也可以购买它,然后在同一天出售。返回你能获得的最大利润 。
思路:相邻两个元素之差为利润,正利润的累加即是可获取的最大利润。
int maxProfit(vector<int>& prices) {
int profit = 0;
for (int i = 0; i < prices.size() - 1; i++)
if (prices[i + 1] - prices[i] > 0) profit += prices[i + 1] - prices[i];
return profit;
}
189、旋转数组
给定一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
void rotate(vector<int>& nums, int k) {
vector<int> v;
k = k % nums.size(); //小坑
for (int i = nums.size() - k; i < nums.size(); i++) {
v.push_back(nums[i]);
}
for (int i = 0; i < nums.size() - k; i++) {
v.push_back(nums[i]);
}
nums = v;
}
//解法二:多次翻转
void reverse(vector<int>& nums, int start, int end) {
while (start < end) {
swap(nums[start], nums[end]);
start += 1;
end -= 1;
}
}
void rotate(vector<int>& nums, int k) {
k %= nums.size();
reverse(nums, 0, nums.size() - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, nums.size() - 1);
}
136、存在重复元素
给你一个整数数组 nums 。如果任一值在数组中出现至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false。
bool containsDuplicate(vector<int>& nums) {
sort(nums.begin(), nums.end());
bool tmp = false;
for (int i = 0; i < nums.size() - 1; i++) {
if (nums[i + 1] - nums[i] == 0) {
tmp = true;
}
}
return tmp;
}
//解法二
bool containsDuplicate(vector<int>& nums) {
sort(nums.begin(), nums.end());
// unique返回非重复元素的下一个元素,end()返回最后一个元素的后一个位置
return std::unique(nums.begin(), nums.end()) != nums.end();
}
350、只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
int singleNumber(vector<int>& nums) {
int result = 0;
for (int i = 0; i < nums.size(); i++) result ^= nums[i];
return result;
}
非常巧妙的一题,看完解法惊掉下巴~~
350、两个数组的交集
给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。
思路一
-
先对两个数组进行排序,然后使用两个指针,分别指向两个数组开始的位置。
-
如果两个指针指向的值相同,说明这个值是他们的交集,就把这个值加入到数组中,然后两个指针在分别往后移一步。
-
如果两个指针指向的值不同,那么指向的值相对小的往后移一步,相对大的先不动,然后再比较。一直重复上面的操作,直到其中一个指针不能再移动为止。
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
vector<int> v;
int i = 0, j = 0;
while (i < nums1.size() && j < nums2.size()) {
if (nums1[i] < nums2[j]) {
i++;
} else if (nums1[i] > nums2[j]) {
j++;
} else {
v.push_back(nums1[i]);
i++;
j++;
}
}
return v;
}
//迭代器
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
vector<int> v;
for (auto it1 = nums1.begin(), it2 = nums2.begin();
it1 != nums1.end() && it2 != nums2.end();) {
if (*it1 < *it2) {
it1++;
} else if (*it1 > *it2) {
it2++;
} else {
v.push_back(*it1);
it1++;
it2++;
}
}
return v;
}
思路二
//hashmap
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
map<int, int> mp;
vector<int> v;
for (int i = 0; i < nums1.size(); i++) {
if (mp[nums1[i]]) {
mp[nums1[i]]++;
} else {
mp[nums1[i]] = 1;
}
}
for (int i = 0; i < nums2.size(); i++) {
if (mp.count(nums2[i])) {
v.push_back(nums2[i]);
mp[nums2[i]]--;
if (mp[nums2[i]] == 0) {
mp.erase(nums2[i]);
}
}
}
return v;
}
66、加一
给定一个由 整数 组成的非空数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。你可以假设除了整数 0 之外,这个整数不会以零开头。
vector<int> plusOne(vector<int>& digits) {
int len = digits.size();
for (int i = len - 1; i >= 0; i--) {
if (digits[i] == 9) {
digits[i] = 0;
} else {
digits[i]++;
return digits;
}
}
digits.insert(digits.begin(), 1);
return digits;
}
283、移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
//双指针
void moveZeroes(vector<int>& nums) {
int left = 0, cnt = 0, len = nums.size();
for (int right = 0; right < len; right++) {
if (nums[right] != 0) {
nums[left] = nums[right];
left++;
} else
cnt++;
}
for (int i = len - 1; i > len - cnt - 1; i--) {
nums[i] = 0;
}
}
//改进版本
void moveZeroes(vector<int>& nums) {
int left = 0, cnt = 0, len = nums.size();
for (int right = 0; right < len; right++) {
if (nums[right] != 0) {
swap(nums[right], nums[left]);
left++;
}
}
}
把非零元素移到前面,再在最后补0。
1、两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
//O(n^2)
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> v;
for (int i = 0; i < nums.size(); i++) {
for (int j = i + 1; j < nums.size(); j++)
if (nums[i] + nums[j] == target) {
v.push_back(i);
v.push_back(j);
break;
}
}
return v;
}
//hash
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hashTable;
for (int i = 0; i < nums.size(); i++) {
hashTable[nums[i]] = i;
}
for (int i = 0; i < nums.size(); i++) {
auto it = hashTable.find(target - nums[i]);
if (it != hashTable.end() && (it->second) != i) {
return {it->second, i};
}
}
return {};
}
36、有效的数独(*)
请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
- 数字 1-9 在每一行只能出现一次。
- 数字 1-9 在每一列只能出现一次。
- 数字 1-9 在每一个以粗实线分隔的
3x3
宫内只能出现一次。(请参考示例图)
注意:
- 一个有效的数独(部分已被填充)不一定是可解的。
- 只需要根据以上规则,验证已经填入的数字是否有效即可。
- 空白格用 ‘.’ 表示。
bool isValidSudoku(vector<vector<char>>& board) {
int row[9][9]; //行数组,第二维记录数字出现的个数
int col[9][9];
int box[3][3][9]; //九宫格数字记录
memset(row, 0, sizeof(row));
memset(col, 0, sizeof(col));
memset(box, 0, sizeof(box));
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
char c = board[i][j]; //当前元素
if (c != '.') {
//下标
int index = c - '0' - 1;
row[i][index]++;
col[j][index]++;
box[i / 3][j / 3][index]++;
if (row[i][index] > 1 || col[j][index] > 1 ||
box[i / 3][j / 3][index] > 1) {
return false;
}
}
}
}
return true;
}
48、旋转图像
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
//画图,查看矩阵特点
void rotate(vector<vector<int>>& matrix) {
int row = matrix.size();
for (int i = 0; i < row; i++) {
for (int j = i + 1; j < row; j++) {
swap(matrix[i][j], matrix[j][i]);
}
}
for (int i = 0; i < row; i++) {
for (int j = 0; j < row / 2; j++) {
swap(matrix[i][j], matrix[i][row - j - 1]);
}
}
}
先转置再镜像。