LeetCode 2016 327,315,372,368,363,330,239

327 Count of Range Sum

// See the discuss
// See the analysis and using the code from:
// http://www.cnblogs.com/jdneo/p/5388501.html
// It is a solution combining the two pointers & merge sort
// There's the analysis from the page
/*
    这道题最直观的一个想法就是枚举出所有的子数组,然后检查他们是否在要求的取值范围内,这种方法的时间复杂度是O(n^2)的,显然会超时。

    看到这种题目最容易想到的是什么呢?Two Pointers!对,但是在这道题上仅仅使用Two Pointers肯定是不够的,在Two Pointers的思想基础上,融合归并排序,就能找到一个比较好的解决方案。

    这里我们的排序对象是前缀求和数组,在归并排序的合并阶段,我们有左数组和右数组,且左和右数组都是排好序的,所以我们可以用i遍历左数组,j,k两个指针分别取在右数组搜索,使得:

    sums[j] - sums[i] < upper
    sums[k] - sums[i] >= lower
    那么此时,我们就找到了j-k个符合要求的子数组。
    
    The vital sentence: so the values from sums[] are placed in increasing order
    由于左右数组都是排好序的,所以当i递增之后,j和k的位置不用从头开始扫描。

    最后还有一点需要注意的就是,为了防止溢出,我们的vector容纳的是long long型元素。
*/

// TLE version 1
// using two pointers, and sum[i] represents the sum from
// element 0 to element i

// TLE version 2
// using Segment tree 55/61 passed, the left 6 points are TLE

class Solution {
public:
    vector<long long> sums;
    int lowBound , upBound;
    int countRangeSum(vector<int>& nums, int lower, int upper)
    {
        int lnums = nums.size();
        if (lnums == 0) return 0;
        lowBound = lower;upBound = upper;
        sums.clear();sums.resize(lnums+1);sums[0]=0;
        for(int i=0;i<lnums;i++)
            sums[i+1]=sums[i]+nums[i];
        return mergeSum(0,lnums);
    }
    int mergeSum(int st, int ed)
    {
        if (st >= ed) return 0;
        int mid = st + (ed - st) / 2;
        int result = mergeSum(st,mid) + mergeSum(mid+1,ed);
        vector<long long> tmp(ed-st+1,0);
        int j = mid +1,k =mid +1, t=mid +1, i=st , r=0;
        for(;i<=mid;i++,r++)
        {
            while(j<=ed && sums[j]-sums[i]<=upBound) j++;
            while(k<=ed && sums[k]-sums[i]<lowBound) k++;
            result += j-k;
            while (t<=ed && sums[t]<=sums[i]) tmp[r++] = sums[t++];
            tmp[r]=sums[i];
        }
        for(int i=0;i<r;i++)
            sums[st+i] = tmp[i];
        return result;
    }
};

315 Count of Smaller Numbers After Self

// Seeing the Discuss & Searching for solution
// Quote the vital sentence:
// """  The smaller numbers on the right of a number are exactly
//      those that jump from its right to its left during a stable sort.
//      So I do mergesort with added tracking of those right-to-left jumps."""
// smaller[] is to record the result
// the second value of enum/left/right is the original location of the value
// the original locaiton must be recorded
// The code:
/*
def countSmaller(self, nums):
    def sort(enum):
        half = len(enum) / 2
        if half:
            left, right = sort(enum[:half]), sort(enum[half:])
            m, n = len(left), len(right)
            i = j = 0
            while i < m or j < n:
                if j == n or i < m and left[i][1] <= right[j][1]:
                    enum[i+j] = left[i]
                    smaller[left[i][0]] += j
					# 想了好久为什么是加上j,也就是加上right当前的下标
					# 手动试了下,当选择右边作为小的时候,左边所有剩下没有被选的,
					# smaller 都要 +1
					# 作者采用的方式就是当选择左边的,
					# 说明之前右边被merge过的,都比左边当前的小,所以加上右边剩下的个数
                    i += 1
                else:
                    enum[i+j] = right[j]
                    j += 1
        return enum
    smaller = [0] * len(nums)
    sort(list(enumerate(nums)))
    return smaller
*/

// Merge sort TLE
// I've tried a version of merge sort
// but there are 2 points I cannot pass.

// Modified the python code from Discuss, 15/16 passed, 1 point TLE
// Do not copy the huge/tremendous vector num during the 
// MergeSortPartial/recursion, it will take tremendous time
// then causes TLE

class Solution {
public:
    // num vector, pair->first the value, pair->second the original location
    vector<pair<int,int> > num;
    vector<int> ans;
    int len;
    void mergeSort(int left, int right)
    {
        //cout<<"sort"<<endl;
        if (left >= right) return ;
        int mid = left +(right - left)/2;
        mergeSort(left,mid);
        mergeSort(mid+1,right);
        mergeSortPartial(left,right);
        return ;
    }
    void mergeSortPartial(int left,int right)
    {
        //cout<<"partial"<<endl;
        //cout<<left<<"  "<<right<<endl;
        if (left >= right) return ;
        vector<pair<int,int> > tmp;tmp.clear();
        int mid = left + (right - left)/2;
        int i = left, j = mid + 1, index = left;
        while(i<=mid && j<=right)
        {
            if (num[i].first <= num[j].first)
            {
                ans[num[i].second] += j-1-mid;
                tmp.push_back(num[i++]);
            }
            else
            {
                tmp.push_back(num[j++]);
            }
        }
        while(i<=mid)
        {
            ans[num[i].second] += j-1-mid;
            tmp.push_back(num[i++]);
        }
        while(j<=right)
        {
            tmp.push_back(num[j++]);
        }
        for(int i=left;i<=right;i++)
        {
            num[i]=tmp[i-left];
        }
        return ;
    }
    void initial(vector<int> nums)
    {
        len = nums.size();
        ans.resize(len);
        num.resize(len);
        for(int i=0;i<len;i++)
        {
            num[i].first = nums[i];
            num[i].second = i;
            ans[i]=0;
        }
        return ;
    }
    vector<int> countSmaller(vector<int>& nums)
    {
        initial(nums);
        mergeSort(0,len-1);
        return ans;
    }
};

372 Super Pow

// Seeing the Discuss & Searching for the Solution
// The analysis from the Discuss
// """
//  One knowledge: ab % k = (a%k)(b%k)%k
//  Since the power here is an array, we'd better handle it digit by digit.
//  One observation:
//  a^1234567 % k = (a^1234560 % k) * (a^7 % k) % k
//      = (a^123456 % k)^10 % k * (a^7 % k) % k
//  Looks complicated? Let me put it other way:
//  Suppose f(a, b) calculates a^b % k; Then translate above formula to using f :
//  f(a,1234567) = f(a, 1234560) * f(a, 7) % k = f(f(a, 123456),10) * f(a,7)%k;
// """
// the code
/*
class Solution {
    const int base = 1337;
    int powmod(int a, int k) //a^k mod 1337 where 0 <= k <= 10
    {
        a %= base;
        int result = 1;
        for (int i = 0; i < k; ++i)
            result = (result * a) % base;
        return result;
    }
public:
    int superPow(int a, vector<int>& b) {
        if (b.empty()) return 1;
        int last_digit = b.back();
        b.pop_back();
        return powmod(superPow(a, b), 10) * powmod(a, last_digit) % base;
    }
};
*/

// The things learned:
// 1. vector has the function
//      .pop_back(): pop the back element
//      .back(): get the value of back element
class Solution {
public:
    const int base = 1337;
    int powmod(int a,int k)
    // return the value of a^k mod 1337
    //  0<=k<10
    {
        a %=base;
        int result = 1;
        for (int i=0;i<k;i++)
            result = a*result %base;
        return result;
    }
    int superPow(int a, vector<int>& b)
    {
        if (b.empty()) return 1;
            int last_digit = b.back();
        b.pop_back();
        return powmod(superPow(a,b),10) * powmod(a,last_digit) % base;
    }
};

368 Largest Divisible Subset

class Solution {
public:
    vector<int> largestDivisibleSubset(vector<int>& nums)
    {
        vector<int> ans; ans.clear();
        int len = nums.size();
        if (len == 0) return ans;
        int maxLen = 0;
        int maxIndex = 0;
        vector<int> f(len,0);
        vector<int> route(len);
        sort(nums.begin(),nums.end());
        for(int i=0;i<len;i++) route[i]=i;
        f[0]=1;
        for(int i=1;i<len;i++)
        {
            for(int j=0;j<i;j++)
            {
                if (nums[i]%nums[j] == 0)
                {
                    if (f[j]>f[i])
                    {
                        f[i]=f[j];
                        route[i]=j;
                    }
                }
            }
            f[i]++;
            if(f[i]>maxLen)
            {
                maxLen =  f[i];
                maxIndex = i;
            }
        }
        while(route[maxIndex]!=maxIndex)
        {
            cout<<maxIndex<<endl;
            ans.push_back(nums[maxIndex]);
            maxIndex = route[maxIndex];
        }
        ans.push_back(nums[maxIndex]);
        sort(ans.begin(),ans.end());
        return ans;
    }
};


363 Max Sum of Rectangle No Larger Than K

/*-------Seeing Discuss & Searching for Solution-------
The discuss is fabulous!
1. Analysis
1.1 Given an array of integers A and an integer k,
    find a subarray that contains the largest sum,
    subject to a constraint that the sum is less than k?
    url:https://www.quora.com/Given-an-array-of-integers-A-and-an-integer-k-find-a-subarray-that-contains-the-largest-sum-subject-to-a-constraint-that-the-sum-is-less-than-k

    Solution:
    You can do this in O(nlog(n))O(nlog⁡(n))
    First thing to note is that sum of subarray (i,j](i,j]
    is just the sum of the first jj elements less the sum of the
    first ii elements. Store these cumulative sums in the array cum.

    Then the problem reduces to finding  i,ji,j such that i<ji<j and
    cum[j]−cum[i]cum[j]−cum[i] is as close to kk but lower than it.
    To solve this, scan from left to right. Put the cum[i]cum[i] values
    that you have encountered till now into a set. When you are processing
    cum[j]cum[j] what you need to retrieve from the set is the smallest
    number in the set such which is bigger than cum[j]−kcum[j]−k. This
    lookup can be done in O(logn)O(log⁡n) using upper_bound. Hence the
    overall complexity is O(nlog(n))O(nlog⁡(n)).

    Here is a c++ function that does the job, assuming that K>0 and that
    the empty interval with sum zero is a valid answer. The code can be
    tweaked easily to take care of more general cases and to return the
    interval itself.

    Code:
    int best_cumulative_sum(int ar[],int N,int K)
    {
        set<int> cumset;
        cumset.insert(0);
        int best=0,cum=0;
        for(int i=0;i<N;i++)
        {
            cum+=ar[i];
            set<int>::iterator sit=cumset.upper_bound(cum-K);
            if(sit!=cumset.end())best=max(best,cum-*sit);
            cumset.insert(cum);
        }
        return best;
    }

1.2 1D -> 2D
    first  consider the situation matrix is 1D
    we can save every sum of 0~i(0<=i<len) and binary search previous sum to find
    possible result for every index, time complexity is O(NlogN).
    so in 2D matrix, we can sum up all values from row i to row j and create a 1D array
    to use 1D array solution.
    If col number is less than row number, we can sum up all values from col i to col j
    then use 1D array solution.

1.3 Process
    For the row may be much greater than the col, so counting the sum of rows.
    For each col, every time each col being a start column;
        Then calculate all the row sums
        For the sums, using set bound to find the iterator then update the value

1.4 Grammar Learned
    c++ set has the function:
        .lower_bound()
        .upper_bound()
        using:
            set<int>::iterator sit=cumset.upper_bound(cum-K);

*/
class Solution {
public:
    int maxSumSubmatrix(vector<vector<int> >& matrix, int k)
    {
        int row = matrix.size();
        if (row == 0) return 0;
        int ans = INT_MIN;
        int col =matrix[0].size();
        for(int cStart=0;cStart<col;cStart++)
        {
            vector<int> sums(row,0);
            for(int c =cStart;c<col;c++)
            {
                // calculate row sums for col from cStart to c
                for(int r = 0;r<row;r++)
                {
                    sums[r]+=matrix[r][c];
                }
                set<int> sumsSet;sumsSet.clear();
                
                // Vital!
                // insert the 0 value in case of 
                // the curSum is equal as the value of k
                sumsSet.insert(0);
                int curSum = 0 ;
                for(int sum:sums)
                {
                    curSum+=sum;
                    set<int>::iterator it = sumsSet.lower_bound(curSum-k);
                    if (it!=sumsSet.end())
                    {
                        ans = max(ans,curSum - *it);
                    }
                    sumsSet.insert(curSum);
                }
            }
        }
        return ans;
    }
};

330 Patching Array

// ---------- Seeing the Discuss------------------ 
/*
	1. Analysis
	"""Let miss be the smallest sum in [0,n] that we might be missing. 
	Meaning we already know we can build all sums in [0,miss). 
	Then if we have a number num <= miss in the given array, 
	we can add it to those smaller sums to build all sums in [0,miss+num). 
	If we don't, then we must add such a number to the array, and 
	it's best to add miss itself, to maximize the reach."""
	The thinking is same as me, but I failed in two aspects:
		(1) I use the vector to tag the values that can be formed
		(2) another solution, I thought, it may only use 1,2,4,8,16,32,.....
			but, the correct solution is some thought of this.
	
	2. Code
	int minPatches(vector<int>& nums, int n) {
    long miss = 1, added = 0, i = 0;
    while (miss <= n) {
        if (i < nums.size() && nums[i] <= miss) {
            miss += nums[i++];
        } else {
            miss += miss;
            added++;
        }
    }
    return added;
}
*/

class Solution {
public:
    int minPatches(vector<int>& nums, int n) 
    {
        int len = nums.size();
        long long missing = 1, i=0,ans =0;
        while(missing <= n)
        {
            if (i<len && nums[i]<=missing)
            {
                // This means the elements are less than missing,
                // so the range can increase to [0,missing+nums[i])
                missing +=nums[i++];
            }
            else
            {
                // 1. Adding new element
                // This means now there are two part can be reached
                // the left part: [0, missing + sum(nums[k])), where nums[k]<=missing for k = [0..i]
                // the right part: [nums[i+1],........) 
                // the middle part cannot be reached: 
                // between missing and nums[i+1],
                // so we have to add the value missing itself
                // 2. The following
                // After missing has been added,
                // the range is [0,missing], for we can using 0,1,...,missing
                // to make the range to [0,missing+missing],
                // that is why missing +=missing
                missing += missing;
                ans++;
            }
        }
        return ans;
    }
};
// ------------------------Two failing solution--------------------------------

// ----------1st attempt: RE----------
// the size of vector is to huge 
class Solution {
public:
    vector<bool> flag; // true for not achieving values
    set<int> values;
    int cnt, len;
    void insertValue(int x,int n)
    {
        if (x>n || x ==0 || !flag[x]) return ;
        flag[x]=false;
        cnt++;
        values.insert(x);
        //cout<<"insert val = "<<x<<endl;
        return ;
    }
    void printValues()
    {
        set<int>::iterator it;
        for(it=values.begin();it!=values.end();it++)
        {
            cout<<(*it)<<endl;
        }
        return ;
    }
    void initial(vector<int>& nums,int n)
    {
        len = nums.size();
        cnt = 0;
        values.clear();
		//-------------Runtime Error------------
        // the size of the vector is too huge
        // when n = 2147483647, causing RE
        flag.clear(); flag.resize(n+1);
        for(int i=0;i<=n;i++) flag[i]=true;
        sort(nums.begin(),nums.end());
        if (len == 0) return ;
		
        // Using bit manipulation to generate the combinations
        // eg: 0001 means there are four items nums[0..3], 
        // and nums[0] was chosen;
        // eg: 1100 means nums[4],nums[3] were chosen. 
        int biStart = 1, biEnd = (1<<len)-1;
        for(int i=biStart;i<=biEnd;i++)
        {
            int p = i,index = 0,curSum = 0;
            while(p!=0)
            {
                if ((p&1)==1) curSum +=nums[index];
                index++;
                p = p>>1;
            }
            insertValue(curSum,n);
        }
        //printValues();
        return ;
    }
    void insertValueToAll(int val,int n)
    {
        set<int> tmpSet = values;
        for(set<int>::iterator it = tmpSet.begin();it!=tmpSet.end();it++)
        {
            insertValue((*it)+val,n);
        }
        insertValue(val,n);
        return ;
    }
    int minPatches(vector<int>& nums, int n)
    {
        initial(nums,n);
        if (cnt == n) return 0;
        int last = 1;
        int ans = 0;
        while(cnt!=n)
        {
            while(!flag[last]) last++;
            insertValueToAll(last,n);
            //cout<<"last = "<<last<<endl;
            //cout<<"cnt = "<<cnt<<endl;
            ans++;
            last++;
        }
        return ans;
    }
};

// 2nd attempt : WA
// using the properties of binary
class Solution {
public:
    int minPatches(vector<int>& nums, int n) 
    {
        set<int> values;
        values.clear();
        int len = nums.size();
        for(int i=0;i<len;i++)
            values.insert(nums[i]);
        long long bit = 1;
        int cnt = 0;
        while(bit<n) 
        {
            //cout<<bit<<endl;
            if (values.find(bit)==values.end())
                cnt++;
            bit = bit<<1;
        }
        cnt--;
        //cout<<cnt<<endl;
        return cnt;
    }
};

239 Sliding Window Maximum

// Using multiset
// Has to using the max value from a set, so using the reverse
//		multiset<int>::reverse_iterator it = window.rbegin();

class Solution {
private:
    multiset<int> window;
    void push(int x)
    {
        window.insert(x);
        return ;
    }

    void pop(int x)
    {
        multiset<int>::iterator it = window.find(x);
        window.erase(it);
        return ;
    }

    int getMax()
    {
        multiset<int>::reverse_iterator it = window.rbegin();
        return (*it);
    }

public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> ans;
        int len=nums.size();
        if (len==0) return ans;
        window.clear();
        for(int i=0;i<k;i++)
        {
            push(nums[i]);
        }
        ans.push_back(getMax());
        int kt=k-1,lent=len-1;
        for(int left=0,right=k;right<len;left++,right++)
        {
            pop(nums[left]);
            push(nums[right]);
            ans.push_back(getMax());
        }
        return ans;
    }
};








  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值