您的位置:首页 > 产品设计 > UI/UE

leetcode 713. Subarray Product Less Than K & leetcode 467. Unique Substrings in Wraparound String

2018-03-02 21:30 429 查看

写在前面

两道类似的题目,解法不一样(哭笑不得.jpg),一道用slidingwindow解,一道DP。

713. Subarray Product Less Than K

题目描述

Your are given an array of positive integers nums.

Count and print the number of (contiguous) subarrays where the product of all the elements in the subarray is less than k.

Example 1:

Input: nums = [10, 5, 2, 6], k = 100

Output: 8

Explanation: The 8 subarrays that have product less than 100 are: [10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6].

Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k.

Note:

0 < nums.length <= 50000.

0 < nums[i] < 1000.

0 <= k < 10^6.

思路分析

这种题目做的非常多了,首先清楚的一点,包含当前元素的连续子数组个数刚好等于当前子数组长度(假设数组是 1,2,3,4 ,则包含4的子集合分别是{4},{3,4},{2,3,4},{1,2,3,4}),这个性质可以通过动态规划推导出来,在很多题目中都用到了,包括这里的两道题,有必要自己推导一下。

刚看到这题的时候第一反应就是用动态规划。首先存储所有前序数的乘积,然后用动态规划方法去找第一个满足条件的子数组,这种方法无疑是可解的。但是,这种方法有着致命缺陷,即必须提前计算出数组中所有元素的乘积,在本题中,直接导致了结果溢出。事实上,提前计算所有的乘积是不必要的,因为乘积的左侧边界事实上是一直在向前移动的(考虑到子数组连续的原因,若一个左侧边界导致乘积大于K,则它必然导致之后的子数组乘积大于K,因此需要向前移动),这就是slidingwindow的解法。因此,动态规划方法中每次都从最左侧开始判断的策略并不需要。

我们分别给出slidingwindow和dp的解法,供参考。注意动态规划对本题不适用。

DP:

class Solution {
public:
int numSubarrayProductLessThanK(vector<int>& nums, int k) {
// 乘法超范围
vector<int> dp(nums.size()+1,0);
// end with i
vector<long long> dup;
for(auto val:nums) dup.push_back(val);
dup.insert(dup.begin(),1);
for(int i= 1;i<dup.size();++i) {
dup[i]*=dup[i-1];
}
for(int i = 1;i<dup.size();++i)
for(int j = 0;j<i;++j) {
if((dup[i]/dup[j])<k) {
dp[i] = i-j;
break;
}
}
return accumulate(dp.begin(),dp.end(),0);
}
};


slidingwindow:

class Solution {
public:
int numSubarrayProductLessThanK(vector<int>& nums, int k) {
if(k<=1) return 0;
int ret = 0;
int p = 1;
int left = 0;
for(int i = 0;i<nums.size();++i) {
p*=nums[i];
while(left<=i&&p>=k) p/=nums[left++];
ret+= i-left+1;
}
return ret;
}
};


467. Unique Substrings in Wraparound String

题目描述

Consider the string s to be the infinite wraparound string of

“abcdefghijklmnopqrstuvwxyz”, so s will look like this:

“…zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd….”.

Now we have another string p. Your job is to find out how many unique non-empty substrings of p are present in s. In particular, your input is the string p and you need to output the number of different non-empty substrings of p in the string s.

Note: p consists of only lowercase English letters and the size of p might be over 10000.

Example 1:

Input: “a”

Output: 1

Explanation: Only the substring “a” of string “a” is in the string s.

Example 2:

Input: “cac”

Output: 2

Explanation: There are two substrings “a”, “c” of string “cac” in the string s.

Example 3:

Input: “zab”

Output: 6

Explanation: There are six substrings “z”, “a”, “b”, “za”, “ab”, “zab” of string “zab” in the string s.

思路分析

这题跟上题非常相近,是同一类型的题目,但对于本题,多出的限制就是子数组不能相同,这就直接导致slidingwindow式的解法无法解决这个问题,相反DP可以解决这个问题,动态规划只考虑以固定字母结尾的最大长度(长度即是子数组个数,上面已经说明),因此不需要考虑重复性(已经自动筛除),考虑所有的26个字母,有以下解法:

DP:

class Solution {
public:
int findSubstringInWraproundString(string p) {

if(p.empty()) return 0;
int res = 0;
vector<int> dp(26,0);
for(int i = 0;i<p.size();++i) {
if(i>0&&(p[i-1]+1==p[i]||((p[i-1]+1-'a')%26)==p[i]-'a')) {
res++;
}
else res = 1;
dp[p[i]-'a'] = max(dp[p[i]-'a'],res);
}
return accumulate(dp.begin(),dp.end(),0);
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: