Leetcode题库练习笔记(Hard)美区&国区

Median of Two Sorted Arrays

Given two sorted arrays nums1 and nums2 of size m and n respectively, return the median of the two sorted arrays.

The overall run time complexity should be O ( l o g ( m + n ) ) O(log (m+n)) O(log(m+n)).

要求返回两个有序数组的中位数,并且时间复杂度控制在 O ( l o g ( m + n ) ) O(log (m+n)) O(log(m+n)).
PS:当然,排序默认都是从小到大
用sort()函数不加参数都是从小到大排序

复杂度O(nlog(n))的解法

这个次优的解法很好想也很好实现,将两个数组合并后排序,再直接输出中位数就行

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        vector<int> nums;
        int i;
        for(i=0;i<nums1.size();i++)
            nums.push_back(nums1[i]);
        for(i=0;i<nums2.size();i++)
            nums.push_back(nums2[i]);
        sort(nums.begin(),nums.end());
        int n=nums.size();
        if(n%2==1)//odd elements
            return nums[(n+1)/2-1];
        else return (nums[n/2-1]+nums[n/2])/2.;        
    }
};

最优题解

时间复杂度为O(log(n+m))
分治解法(Devide and Conquer):

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m=nums1.size();
        int n=nums2.size();
        int k1=(m+n+1)/2;
        int k2=(m+n+2)/2;
        return (getKth(nums1,nums2,0,0,k1)+getKth(nums1,nums2,0,0,k2))/2.;
    }
    #define MAX 0x7FFFFFFF
    double getKth(vector<int>& nums1, vector<int>& nums2,int start1,int start2,int k)
        //return the kth element of combined vector num1&num2
        //binary search+recursion
    {
          //one of them is vacant
          if(start1>=nums1.size())return nums2[start2+k-1];
          if(start2>=nums2.size())return nums1[start1+k-1];
          if(k==1)return min(nums1[start1],nums2[start2]);
            int m=nums1.size()-start1;
            int n=nums2.size()-start2;
          //get midval, the (k/2)th element
            int midVal1,midVal2;
           if(m<k/2)midVal1=MAX;else midVal1=nums1[start1+k/2-1];
           if(n<k/2)midVal2=MAX;else midVal2=nums2[start2+k/2-1];
          //both of them has (k/2)th element
           if(midVal1<midVal2)
               return getKth(nums1,nums2,start1+k/2,start2,k-k/2);
           else
               return getKth(nums1,nums2,start1,start2+k/2,k-k/2);            
    }   
};

解题思路:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
分而减枝:依照题目要求找中位数,可以化归于一个更普适的问题:找出两个有序数组合并后的第k个元素
如上所示,可以递归地分而减枝,每次传入两个数组各自的后半段(start1, start2来定位)和元素下标k。
分情况讨论:

  • 有数组为空:返回另一个数组的[k-1]元素
  • k==1:返回两段段首中较小的那个(因为较小者合并后排在前面,刚好是第一个)
  • 非以上两种情况:对比两段中[k/2]元素,抛下[k/2]较小的那一段的前半段,在剩下部分中继续寻找第k-k/2个元素。
    原因:[k/2]较小意味着[k/2]在内的前半段必然在最终合并后排在第k个元素前面,所以可以抛下不管,在剩下的部分中继续寻找
        ~~~    注意:如果某段[k/2]元素不存在,那就将另一段前半段抛下(排在前面),因为用这样减枝方法留下来的必然是较大的元素,而较小者才应该排到前面。
    程序实现时,将某段前半段抛下 ⇔ ⇔ 将该段start加上k/2后递归调用

Stone Game IV

题目:leetcode Stone Game IV题目
在这里插入图片描述
题目要求:Alice 先行,输出Alice赢与否(bool)
每一步玩家可以移走面前石头中的i个(i是完全平方数1,4,9…),无法如此行动则输
重要隐含条件玩家面前没有石头==输,因为玩家面前的石头数必然是自然数,只要存在石头就可以至少移走1个,从而不在这局输。

解法1 递归解法 DFS:

但是时间复杂度很高,官方解法是python+缓存存储
Python语法糖:@lru_cache(maxsize=none) 启用least-recently-used缓存存储模式,从而提高递归执行速度
这里用到一点计组的知识,cache的页替换策略包含很多种,替换策略汇总
相比传统的FIFO(先进先出)等方式,LRU策略使得代码执行速度更快

class Solution:
    def winnerSquareGame(self, n: int) -> bool:
        @lru_cache(maxsize=None)
        def dfs(remain):
            if remain == 0:
                return False
            sqrt_root = int(remain**0.5)
            for i in range(1, sqrt_root+1):
                # if there is any chance to make the opponent lose the game in the next round,
                #  then the current player will win.
                if not dfs(remain - i*i):
                    return True
            return False
        return dfs(n)

解法2 迭代解法 DP:

上述DFS的等价的迭代版本就是动态规划解法

    bool winnerSquareGame(int n)
    {
        vector<int>dp(n+1);    //initially all zeros 注意一定是开n+1个空位
        for(int i=1;i<=n;i++)
        {
            for(int k=1;k<=sqrt(i);k++)
                if(dp[i-k*k]==false)
                {dp[i]=true;break;}
        }
        return dp[n];
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kaze-1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值