简单篇
1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
<C code>
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
int i = 0;
int j = 0;
int* ret = (int*)malloc(sizeof(int)*2);
for(i=0; i<numsSize; i++)
{
for(j=i+1; j<numsSize; j++)
{
if((nums[i]+nums[j]) == target)
{
ret[0] = i;
ret[1] = j;
*returnSize = 2;
return ret;
}
}
}
*returnSize = 0;
return NULL;
}
<C++ code>
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int n = nums.size();
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
if(nums[i]+nums[j]==target)
{
return {i,j};
}
}
}
return {};
}
};
53. 最大子序和
给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
【核心思想:tmp每次记录以 i 下标为结尾的子数组的最大和】
class Solution { //时间O(n) 空间O(1)
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
int ret = nums[0], tmp = nums[0];
for(int i=1; i<n; i++)
{
tmp = max(nums[i], tmp+nums[i]);//每次tmp记录的是:以i下标结尾的子数组的最大和;
ret = max(ret, tmp);
}
return ret;
}
};
136. 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
int singleNumber(int* nums, int numsSize){ //时间O(n) 空间O(1)
int ret = 0;
int i;
for(i=0; i<numsSize; i++)
{
ret = ret ^ nums[i];
}
return ret;
}
class Solution {
public:
int singleNumber(vector<int>& nums) {
int n = nums.size();
int ret;
sort(nums.begin(), nums.end());
if(n==1)
return nums[0];
for(int i=0; i<n; i+=2)
{
if(i==n-1) //判断是否遍历到最后一个元素
{
ret = nums[i];
break;
}
if(nums[i] != nums[i+1])
{
ret = nums[i];
break;
}
}
return ret;
}
};
169. 多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
class Solution {
public:
int majorityElement(vector<int>& nums) {
//法1
sort(nums.begin(),nums.end());
return nums[nums.size()/2];
//法2
unordered_map<int, int> ret;
for(auto num : nums)
{
ret[num]++;
if(ret[num]>nums.size()/2)
return num;
}
return -1;
//法3 暴力解法;时间复杂度为 O(nlogn)、空间复杂度为 O(logn);
/* int tmp_d=0,tmp_n=0;
int ret_d=0,ret_n=0;
int n=nums.size();
int i=0;
sort(nums.begin(),nums.end());
if(n==1)
return nums[0];
for(int i=0; i<n; i++)
{
if(i==0)
{
tmp_d=nums[i];
tmp_n++;
continue;
}
if(nums[i]==nums[i-1])
{
tmp_n++;
}
else
{
if(ret_n<=tmp_n)
{
ret_n=tmp_n;
ret_d=tmp_d;
}
tmp_d=nums[i];
tmp_n=1;
}
}
if (ret_n < tmp_n)
{
ret_d = tmp_d;
}
return ret_d;
*/
}
};
283. 移动零至数组尾端--双指针思想
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
【核心思想:左指针为0元素段的起始位置,且其左侧均为非0数;右指针左侧到做指针(包含左指针位置)均为0】
void moveZeroes(int* nums, int numsSize){
int left = 0 , right = numsSize-1;
int i;
while(left<right)
{
if(nums[left] == 0)
{
i = left;
while(i<right)
{
nums[i] = nums[i+1];
i++;
}
nums[right--] = 0;
}
else if(nums[left] != 0)
{
left++;
}
}
}
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
void moveZeroes(int* nums, int numsSize){
int left = 0, right = 0;
while(right<numsSize)
{
if(nums[right])
{
swap(nums+left, nums+right);
left++;
}
right++;
}
}
448. 找到所有数组中消失的数字--原地修改
给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。
进阶:你能在不使用额外空间且时间复杂度为 O(n)
的情况下解决这个问题吗? 你可以假定返回的数组不算在额外空间内。
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
int n = nums.size();
for(int i=0; i<n; i++){
int x = (nums[i]-1) % n;
nums[x] += n;
}
vector<int> v;
for(int i=0; i<n; i++){
if(nums[i] <= n){ //注意这里时<=
v.push_back(i+1);
}
}
return v;
}
};
121. 买卖股票的最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
/*
*暴力解法
*/
class Solution {
public:
int maxProfit(vector<int>& prices) {
int left = 0, right = 0;
int n = prices.size();
int ret = 0;
for(int i=0; i<n-1; i++){
if(i!=0 && prices[i]>prices[left]){
//if(prices[i]>prices[left]){
continue;
}
if(prices[i]<prices[i+1]){
left = i;
right = i+1;
while(right<n){
ret = max(prices[right]-prices[left], ret);
right++;
}
}
}
return ret;
}
};
class Solution {
public:
int maxProfit(vector<int>& prices) {
int minprices = 1e9, ret = 0;
for(int i = 0; i<prices.size(); i++)
{
ret = max(ret, prices[i]-minprices);
minprices = min(minprices, prices[i]);
}
return ret;
}
};
中等篇
11. 盛最多水的容器--双指针思想
给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
/* C code */
int maxArea(int* height, int heightSize){
int i = 0, j = heightSize-1; //下标从0开始;
int ret = (j-i) * fmin( height[i], height[j]);
int tmp;
while(i<j)
{
height[i]<height[j] ? i++ : j--;
tmp = (j-i) * fmin(height[i],height[j]);
ret = fmax(ret,tmp);
}
return ret;
}
/* C++ code */
class Solution {
public:
int maxArea(vector<int>& height) {
int l = 0, r = height.size() - 1;
int ret = 0;
while(l<r)
{
ret = max( ret, min(height[l], height[r]) * (r-l) );
height[l]<height[r] ? l++ : r--;
}
return ret;
}
};
15. 三数之和--排序+双指针
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
vector<vector<int>> ret;
//if(n<3)
// return ret;
for(int first=0; first<n; first++) //第1目标a
{
if(first>0 && nums[first]==nums[first-1]) //!!!
continue;
int third = n-1; //!!!目标3的标记,要在第2阶循环前设置;
for(int second=first+1; second<n; second++) //第2目标b
{
if(second>first+1 && nums[second] == nums[second-1]) //!!!
continue;
while(third>second && nums[first]+nums[second]+nums[third]>0)//第3目标c 注意条件!!!
{
third--;
}
if(third==second)
break;
if(nums[first]+nums[second]+nums[third] == 0)
ret.push_back({nums[first],nums[second],nums[third]});
}
}
return ret;
}
};