1.快速排序
函数代码:
//快速排序
#include <iostream>
using namespace std;
void quicksort(int arr[],int left,int right)
{
int i;
int j;
int pivot;
if(left>right)
{
return;
}
if(left<right)
{
//pivot存基准数
pivot=arr[left];
i=left;
j=right;
while(i<j)
{
//要从右边开始,这点很重要,别忽略了
while(i<j&&arr[j]>=pivot)
{
--j;
}
if(i<j)
{
//把比pivot小的元素移到左边
arr[i++]=arr[j];
}
while(i<j&&arr[i]<=pivot)
{
++i;
}
if(i<j)
{
//把比pivot大的元素移到右边
arr[j--]=arr[i];
}
}
//pivot移到最终位置
arr[i]=pivot;
//继续处理左边的,对左区间进行递归排序
quicksort(arr,left,i-1);
//继续处理右边的,对右区间进行递归排序
quicksort(arr,i+1,right);
}
}
int main()
{
int arr[9]={6,2,7,9,3,1,5,4,8};
//快速排序之前
cout<<"快速排序之前:"<<endl;
for(int i=0;i<9;++i)
{
cout<<arr[i]<<" ";
}
cout<<endl;
quicksort(arr,0,8);
//快速排序之前后
cout<<"快速排序之后:"<<endl;
for(int i=0;i<9;++i)
{
cout<<arr[i]<<" ";
}
cout<<endl;
}
2.二分查找
函数代码:
//标准二分查找
int binarysearch(int nums[],int k)
{
int left=0;
int right=nums.size()-1;
while(left<=right)
{
int mid=left+(right-left)/2;
if(nums[mid]==k)
{
return mid;
}
else if(nums[mid]<k)
{
l=mid+1;
}
else
{
r=mid-1;
}
}
return left;
}
函数代码:
//查找左边界
int binarysearch(int nums[],int k)
{
int left=0;
int right=nums.size()-1;
while(left<=right)
{
int mid=left+(right-left)/2;
if(nums[mid]==k)
{
r=mid-1;
}
else if(nums[mid]<k)
{
l=mid+1;
}
else
{
r=mid-1;
}
}
return left;
}
函数代码:
//查找右边界
int binarysearch(int nums[],int k)
{
int left=0;
int right=nums.size()-1;
while(left<=right)
{
int mid=left+(right-left)/2;
if(nums[mid]==k)
{
l=mid+1;
}
else if(nums[mid]<k)
{
l=mid+1;
}
else
{
r=mid-1;
}
}
return left;
}
3.两数之和
方法一:暴力法,两次遍历
函数代码:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int i,j;
for(i=0;i<nums.size()-1;i++)
{
for(j=i+1;j<nums.size();j++)
{
if(nums[i]+nums[j]==target)
{
return {i,j};
}
}
}
return {i,j};
}
};
方法二:二分查找(利用数组实现双指针)
函数代码:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> temp;
vector<int> res;
int n=nums.size();
temp=nums;
int i=0;
int j=n-1;
sort(temp.begin(),temp.end());
while(i<j)
{
if(temp[i]+temp[j]>target)
{
j--;
}
else if(temp[i]+temp[j]<target)
{
i++;
}
else
{
break;
}
}
if(i<j)
{
for(int k=0;k<n;++k)
{
if(i<n&&nums[k]==temp[i])
{
res.push_back(k);
i=n;
}
else if(j<n&&nums[k]==temp[j])
{
res.push_back(k);
j=n;
}
if(n==i&&n==j)
{
return res;
}
}
}
return res;
}
};
方法三:hashmap(一遍哈希)
函数代码:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> m;
for(int i = 0; i < nums.size(); i++)
{
if(m.find(target-nums[i]) != m.end())
{
//m[target-nums[i]]为已经加入map的元素的索引,所以小于本轮循环中的i,放在前面
return {m[target-nums[i]], i};
}
//向map中添加元素
m[nums[i]] = i;
}
return {};
}
};
二遍哈希
函数代码:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> m;
for(int i = 0; i<nums.size(); i++)
{
//向map中添加元素
m[nums[i]] = i;
}
for(int i = 0; i<nums.size(); i++)
{
//如果m中存在对应的键值,且不为i
if(m.find(target-nums[i])!= m.end()&&m[target-nums[i]]!=i)
{
return {i, m[target-nums[i]]};
}
}
return {};
}
};
4.三数之和
解法和二数之和一样,用二分查找
函数代码:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>>res;
vector<int>path;
sort(nums.begin(),nums.end());
int i=0,mid=i+1,j=nums.size()-1,t;
for(int i=0;nums[i]<=0&&i<nums.size();i++)
{
i=0,mid=i+1,j=nums.size()-1;
t=0-nums[i];
if(i>0&&nums[i]==nums[i-1])
{
continue;
}
while(mid<j)
{
if(nums[mid]+nums[j]==t)
{
int x=nums[mid],y=nums[j];
int z=nums[i];
path.push_back(z);
path.push_back(x);
path.push_back(y);
res.push_back(path);
while(mid<j)
{
if(x==nums[mid])
{
++mid;
}
}
while(mid<j)
{
if(y=nums[j])
{
--j;
}
}
}
else if(nums[mid]+nums[j]<t)
{
++mid;
}
else
{
--j;
}
}
}
return res;
}
};
5.爬楼梯
方法,用递归,有记忆的递归,迭代法
6.合并两个有序数组
函数代码:
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int len=m+n-1;
while(n)
{
if(m==0)
{
nums1[len--]=nums2[--n];
}
else if(nums2[n-1]>nums1[m-1])
{
nums1[len--]=nums2[--n];
}
else
{
nums1[len--]=nums1[--m];
}
}
}
};
解法二
函数代码:
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i=m-1;
int j=n-1;
int l=m+n-1;
while(i>=0&&j>=0)
{
if(nums1[i]>nums2[j])
{
nums1[l--]=nums1[i--];
}
else
{
nums1[l--]=nums2[j--];
}
}
while(j>=0)
{
nums1[l--]=nums2[j--];
}
}
};
方法二:从后往前,交换数据
函数代码:
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i = nums1.size() - 1;
m--;
n--;
while (n >= 0)
{
while (m >= 0 && nums1[m] > nums2[n])
{
swap(nums1[i--], nums1[m--]);
}
swap(nums1[i--], nums2[n--]);
}
}
};
方法三:合并数组,在排序
函数代码:
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
for (int i = 0, j = nums1.size() - 1; i < n && j >= m; i ++, j --)
{
nums1[j] = nums2[i];
}
sort(nums1.begin(),nums1.end());
}
};
7.最大连续子数组之和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
函数代码:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int res=INT_MIN;
vector<int> dp(nums.size(),0);
dp[0]=nums[0];
res=nums[0];
for(int i=1;i<nums.size();i++)
{
dp[i]=max(dp[i-1]+nums[i],nums[i]);
res=max(res,dp[i]);
}
return res;
}
};
8.最长不重复字串
函数代码:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int n=s.size();
int i=0,j,k,res=0;
for(j=0;j<n;j++)
{
for(k=i;k<j;k++)
{
if(s[k]==s[j])
{
i=k+1;
break;
}
}
if(j-i+1>res)
{
res=j-i+1;
}
}
return res;
}
};
9.全排列
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
回溯法(backtrace) :一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解被确认不是一个解的话(或者至少不是最后一个解),回溯算法会通过在上一步进行一些变化抛弃该解,即回溯并且再次尝试。
参考代码1:
class Solution
{
public:
void backtrace(vector<vector<int>>& res,vector<int>& temp,int cnt,int n)
{
//如果cnt与排列数字的长度n相等,把temp数组放入二维数组res
if(cnt==n)
{
res.push_back(temp);
return;
}
for(int i=cnt;i<n;++i)
{
swap(nums[i],nums[cnt]);
// 继续递归填下一个数
dfs(res,temp,cnt+1,n);
//撤销操作,回溯
swap(nums[i],nums[cnt]);
}
}
vector<vector<int>> permute(vector<int> &nums)
{
vector<vector<int>>res;
backtrace(res,temp,0,n);
return res;
}
};
参考代码2:
class Solution {
public:
void backtrace(int depth,int len,vector<int>&used,vector<int>&nums,vector<vector<int>>&res,vector<int> &temp)
{
//递归终止条件,把temp数组放入二维数组
if(depth==len)
{
res.push_back(temp);
return;
}
for(int i=0;i<len;i++)
{
if(!used[i])
{
//记录这个数字被使用
used[i]=1;
//把当前这个数字nums[i]放入临时数组中temp
temp.push_back(nums[i]);
//在当前位是当前数字的情况下,把所有的可能排列结果都找到并放入res
backtrace(depth+1,len,used,nums,res,temp);
//撤销选择,返回上一个选择,开始回溯,清空状态量
used[i]=0;
//弹出这个选择的数字
temp.pop_back();
}
}
return;
}
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> res;
int len=nums.size();
if(len==0)
{
return res;
}
int depth=0;
//记录当前数字是否用过
vector<int> used(len,0);
//申请临时数组,符合排列顺序的数字
vector<int>temp;
//深度优先搜索(DFS)
backtrace(0,len,used,nums,res,temp);
return res;
}
};
10.股票利润最大
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意:你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
函数代码:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len=prices.size();
if(len==0)
{
return 0;
}
int minprice=prices[0];
int maxProfit=0;
for(int i=1;i<len;i++)
{
maxProfit=max(maxProfit,prices[i]-minprice);
if(prices[i]<minprice)
{
minprice=prices[i];
}
}
return maxProfit;
}
};
函数代码2:动态规划
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len=prices.size();
if(len==0)
{
return 0;
}
int minprice=prices[0];
vector<int>dp(len,0);
for(int i=1;i<len;i++)
{
//dp[i]=max(dp[i-1],prices[i]-minprice);
if(prices[i]<minprice)
{
minprice=prices[i];
}
dp[i]=max(dp[i-1],prices[i]-minprice);
}
return dp[len-1];
}
};