常考的十道高频手撕算法题

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];
    }
};
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值