leetcode刷题日记0304

1.Two Sum

0304

很简单能直接想到暴力破解,两重循环,因此复杂度为O(n2)。

也有O(n)的做法,用空间换时间,用一次循环将每个元素值与其对应索引存入哈希表,并在存之前判断,要存的这个元素值是否有对应数在之前已经存进去的,这样就为时间复杂度O(n),空间复杂度为O(n)。

2.Stock Buy 3

0305

首先想着用递归来做

1.首先考虑,基准情况:如果买过两次股票,且手里股票也卖了,终止递归return 0。

2.然后考虑,推进情况:

如果手里有股票,return max(这次卖了的收益+递归下一天且手里没股票的收益,这次不卖直接递归下一天手里没股票的收益)

如果手里没股票,return max(这次买了,递归下一天手里有股票且交易次数+1的收益,这次不买直接递归下一天且手里依旧没股票的收益)

代码如下:

class Solution_recursion{
	public:
		int maxProfit(vector<int>&prices)
		{
			return f(prices,0,0,0);
		 }
	private:
		// i 当前第几天
		// hasStock 是否有股票在手
		// counts 已经交易次数 
		
		int f(vector<int> prices,int i,int hasStock,int counts)
		{
			//如果已经买了两次股票,并且手里没有股票了,后面天数不考虑 
			if(i>=prices.size() || (counts>=2 && hasStock<1))
			{
				return 0;
			}
			//手里有股票还能卖 
			if(hasStock>0)
			{
				return max(prices[i]+f(prices,i+1,0,counts),f(prices,i+1,1,counts)); 
			}
			//手里没股票还能买 
			return max(-prices[i]+f(prices,i+1,1,counts+1),f(prices,i+1,0,counts));
		}
};

然后发现时间复杂度超了,这里递推公式为T(n)=2T(n-1),所以时间复杂度为O(2^n)

后面看评论发现如下思路:

记录当前为第一次买股票时拥有的收益

记录当前为第一次卖股票时拥有的收益

记录当前为第二次买股票时拥有的收益

记录当前为第二次卖股票时拥有的收益

最后第二次卖股票时的收益就是两次交易后的最大收益。

下面给个例子好参考,其实就是把当前进行各种操作的最大收益进行记录。

代码:

class Solution
{
	public:
		int maxProfit(vector<int>& prices)
		{
			//hold1:该天第一次买入股票可获得最大收益 
			//Sell1: 该天第一次卖出股票可获得最大收益
			//hold2:该天第二次买入股票可获得最大收益
			//Sell2:该天第二次卖出股票可获得最大收益
			//分别对四个变量进行更新,最后secSell就是最大收益值
			
			int hold1=INT_MIN,sell1=0;
			int hold2=INT_MIN,sell2=0;
			int day=1;
			for(int p : prices)
			{
				hold1=max(hold1,-p);
				sell1=max(sell1,hold1+p);
				hold2=max(hold2,sell1-p);
				sell2=max(sell2,hold2+p);
				cout << "day" << day << " : " 
				<<hold1<<" "
				<<sell1<<" "
				<<hold2<<" "
				<<sell2<<" "
				<<endl; 
				day++;
			 } 
			return sell2; 
		}
};

时间复杂度为O(n)。

3.Find k-th smallest pair distance

0306

这道题因为差最大就是1000000,所以就直接弄个1000000大小的数组,然后双重循环减一次记录每个差出现的次数,最后就找出第k小对应的下标就是第k小个差。

代码:

class Solution_bucket {
public:
    int smallestDistancePair(vector<int>& nums, int k) {
        int n=nums.size(),N=1000000;
        vector<int> cnt(N,0);
        for(int i=0;i<n;i++)
        {
        	for(int j=i+1;j<n;j++)
        	{
        		cnt[abs(nums[i]-nums[j])]++;
			}
		}
		for(int i=0;i<N;i++)
			{
				if(cnt[i]>=k)return i;
				k-=cnt[i];
			}
		return 0;
    }
};

时间复杂度为O(n2),空间上就耗费多个大小是1000000个int的数组。

参考别人后发现正确应该用binary_search做,时间复杂度可以优化到O(nlogn)

代码:

class Solution_bisearch {
public:
    int smallestDistancePair(vector<int>& nums, int k) {
        sort(nums.begin(),nums.end());
        int n=nums.size(),low=0,high=1000000;
        while(low<high)
        {
            int mid=(low+high)/2,cnt=0;
            for(int i=0,j=0;i<n;i++)
            {
                while(j<n && nums[j]-nums[i] <= mid)j++;
                cnt+=j-i-1;
            }
            if(cnt<k)
            {
                low=mid+1;
            } 
            else
            {
                high=mid;
            }
                
        }
        return low;
    }
};

思想是对要求的第k小个差进行二分,由于按升序排列,看符合a[j]-a[i]<=mid时前面有几个差,多于k时说明差太大,少于k时说明差太小,然后继续二分,考虑下边界情况发现return low就是第k小个差。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值