题目一般从leedcode摘抄来,从简单到复杂
目录
1.简单题目
1.1有效的字母异位词
1.2两个数组的交集
1.3按奇偶排序数组Ⅱ
2.中等题目
2.1三数之和&四数之和
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram"
输出: true
示例 2:
输入: s = "rat", t = "car"
输出: false
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-anagram
方法很多,很容易想到排序之后再比较,比如使用C++ 的STL,或者自己写排序算法。
方法1:排序之后比较
bool isAnagram(string s, string t) {
//先进行排序,后用compare方法比较
sort(s.begin(), s.end());
sort(t.begin(), t.end());
//0=相同,-1=不同
int val = s.compare(t);
return !val;
}
方法2:考虑每个字符对应特定的ASCII码的方式,新开一个26元素大小的数组,遍历两个字符串,每个字符与‘a’做差即为0-26的数字,采用计数的方式比较是否异位。提交结果显示明显比方法1执行用时少。
bool isAnagram(string s, string t){
if(s.length() != t.length()){
return false;
}
int num[26] = {0};
for(int i = 0; i < s.length(); i++){
num[s[i] - 'a']++;
num[t[i] - 'a']--;
}
for (int i : num) {
if(i)
return false;
}
return true;
}
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2]
示例 2:
输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [9,4]
说明:
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/intersection-of-two-arrays
很容易想到先排序,再遍历的方式,要重点关心一下去重操作。(特别注意下标越界的情况,leedcode对这个很敏感)
方法1:
vector intersection(vector& nums1, vector& nums2) {
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
vector res = {};
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 if(nums1[i] == nums2[j]){
res.push_back(nums1[i]);
i++;
j++;
}
//去重
while(i > 0 && i < nums1.size()){ //避免越界
if(nums1[i] == nums1[i - 1]) //如果跟上一个元素相同,下标++
i++;
else
break;
}
}
return res;
}
方法2:使用C++中的set容器,能达到自动去重的效果。
vector intersection(vector& nums1, vector& nums2){
vector res;
set s;
for (int i : nums1) {
//找到时返回下标,找不到返回迭代器结尾
if (find(nums2.begin(), nums2.end(), i) != nums2.end())
{
s.insert(i);
}
}
res.assign(s.begin(),s.end());
return res;
}
给定一个非负整数数组 A, A 中一半整数是奇数,一半整数是偶数。
对数组进行排序,以便当 A[i] 为奇数时,i 也是奇数;当 A[i] 为偶数时, i 也是偶数。
你可以返回任何满足上述条件的数组作为答案。
示例:
输入:[4,2,5,7]
输出:[4,5,2,7]
解释:[4,7,2,5],[2,5,4,7],[2,7,4,5] 也会被接受。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-array-by-parity-ii
这道题的涉及排序、交换,解法肯定很多。我首先找到其中的规律,采用类似插入排序的一种算法
方法1
vector sortArrayByParityII(vector& A){
//先使第0个数是偶数
if(A[0] % 2 != 0){
for(int i = 1; i < A.size(); i++){
if(A[i] % 2 == 0)
swap(A[0], A[i]);
}
}
int count_0 = 1, count_1 = 0; //奇偶计数器
//数组遍历
for(int i = 1; i < A.size(); i++){
int key = A[i];
int j = i - 1;
//当前为偶数
if(key % 2 == 0){
//前一个数是奇数,插入位置应该在偶数数量*2的前面
if(A[i - 1] % 2 != 0){
while(j >= count_0 * 2){
swap(A[j], A[j + 1]);
j--;
}
}
count_0++;
}
//当前为奇数
else{
//前一个数是偶数,插入位置应该在奇数数量*2的后面
if(A[i - 1] % 2 == 0){
while(j > count_1 * 2){
swap(A[j], A[j + 1]);
j--;
}
}
count_1++;
}
}
return A;
}
方法2
两个指针遍历,将两个不符合规定的元素交换(有点快排的意思)
vector sortArrayByParityII(vector& A){
int i = 0, j = 1;
while(i < A.size() - 1 && j < A.size()){
while(i < A.size() - 1){
//遇到奇数就退出循环
if(A[i] % 2 == 0)
i += 2;
else
break;
}
while(j < A.size()){
//遇到偶数就退出循环
if(A[j] % 2 == 1)
j += 2;
else
break;
}
//交换不符合顺序的
if(i < A.size() - 1 && j < A.size())
swap(A[i], A[j]);
i += 2;
j += 2;
}
return A;
}
三数之和:
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
四数之和:
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/4sum
这一类题目刚开始想到的是回溯法,可解,但是会超时,所以采用先将数组排序,然后双指针法。
三数之和:
vector> threeSum(vector& nums) {
vector> res;
if(nums.size() < 3)
return res;
sort(nums.begin(), nums.end());
set> set1;
for(int i = 0; i < nums.size() - 2; i++){
if(i > 0){
if(nums[i] == nums[i - 1])
continue;
}
int left = i + 1, right = nums.size() - 1;
while(left < right){
int sum = nums[i] + nums[left] + nums[right];
if(sum == 0){
vector temp = {nums[i], nums[left], nums[right]};
set1.insert(temp);
left++;
right--;
} else if(sum < 0){
left++;
} else if(sum > 0){
right--;
}
}
}
res.assign(set1.begin(), set1.end());
return res;
}
四数之和:(外层再加一层循环)
vector> fourSum(vector& nums, int target) {
vector> res;
if(nums.size() < 4)
return res;
sort(nums.begin(), nums.end());
set> set1;
for(int i = 0; i < nums.size() - 3; i++){
if(i > 0){
if(nums[i] == nums[i - 1])
continue;
}
for(int j = i + 1; j < nums.size() - 2; j++){
int left = j + 1, right = nums.size() - 1;
while(left < right){
int sum = nums[i] + nums[j] + nums[left] + nums[right];
if(sum == target){
vector temp = {nums[i], nums[j], nums[left], nums[right]};
set1.insert(temp);
left++;
right--;
} else if(sum < target){
left++;
} else if(sum > target){
right--;
}
}
}
}
res.assign(set1.begin(), set1.end());
return res;
}
另外贴出超时的回溯解法:
void traceback(vector& nums, int target, vector> &res, vector &temp, int dep, int begin){
if(dep == 4){
if(target == 0){
res.push_back(temp);
}
return;
}
for(int i = begin; i < nums.size() + (dep - 3); i++){
if(i > begin && nums[i] == nums[i - 1])
continue;
temp.push_back(nums[i]);
traceback(nums, target - nums[i], res, temp, dep + 1, i + 1);
temp.pop_back();
}
}
vector> fourSum(vector& nums, int target) {
vector> res;
if(nums.size() < 4)
return res;
sort(nums.begin(), nums.end());
vector temp;
traceback(nums, target, res, temp, 0, 0);
return res;
}