您的位置:首页 > 其它

DP(5) -- Word Break, Partition Equal Subset Sum,Arithmetic Slices

2017-01-09 21:02 218 查看
Word Break

Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented
into a space-separated sequence of one or more dictionary words. You may assume the dictionary does not contain duplicate words.

For example, given
s = 
"leetcode"
,
dict = 
["leet", "code"]
.

Return true because 
"leetcode"
 can be segmented as 
"leet
code"
.

解法1:DFS。可以递归也可以不用递归去写。遍历搜索的话非常重要的一点是减少空间开辟和销毁的开销,以及避免重复搜索
class Solution {
public:

bool match(int start, string& s, string& word){
for(int i = 0; i < word.size(); i++){
if(s[i+start] != word[i]) return false;
}
return true;
}

bool find(string& s, int start, vector<string>& wordDict, unordered_set<int>& visit){
if(visit.find(start) != visit.end()) return false;
if(start == s.size()) return true;
for(string word: wordDict){
if(word.size() <= s.size() - start && word[0] == s[start])
if(match(start, s, word) && find(s, start+word.size(), wordDict, visit)) return true;
}
visit.insert(start);
return false;
}

bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<int> visit;
return find(s, 0, wordDict, visit);
}
};


解法2:BFS,贴一个优化不太好的解法,主要看思路

bool wordBreak(string s, vector<string>& wordDict) {
// BFS
queue<int> BFS;
unordered_set<int> visited;

BFS.push(0);
while(BFS.size() > 0)
{
int start = BFS.front();
BFS.pop();
if(visited.find(start) == visited.end())
{
visited.insert(start);
for(int j=start; j<s.size(); j++)
{
string word(s, start, j-start+1);
if(find(wordDict.begin(), wordDict.end(), word) != wordDict.end())   //这一部分的搜索是可以优化的,new string和简单的find
{									 //都是很耗时的
BFS.push(j+1);
if(j+1 == s.size()) return true;
}
}
}
}
return false;
}

解法3:DP。记录到i为止是否为满足条件的序列。

class Solution {
public:

bool match(int start, string& s, string& word){  //start为要比较子串的起始在s中的起始位置
for(int i = 0; i < word.size(); i++){
if(s[i+start] != word[i]) return false;
}
return true;
}
bool wordBreak(string s, vector<string>& wordDict) {
vector<bool> dp(s.size()+1);
dp[0] = true;
for(int i = 1; i <= s.size(); i++){
bool valid = false;
for(int j = 0; j < wordDict.size(); j++){
string word = wordDict[j];
if(i >= word.size() && dp[i - word.size()] && match(i - word.size(), s, word)){
valid = true;
break;
}
}
dp[i] = valid;
}
return dp[s.size()];
}
};


Partition Equal Subset Sum

解法1:DP

1. 问题可转化为是否存在subset of nums使得sum = totalSum / 2。

2. 类似背包问题,每个数可能选或者不选。dp[i][j]记录i为止能否使得sum = j.  更新公式为 dp[i][j] = (dp[i][j] || dp[i-1][j-nums[i-1]]);

3. 以下为Java版本

public boolean canPartition(int[] nums) {
int sum = 0;

for (int num : nums) {
sum += num;
}

if ((sum & 1) == 1) {
return false;
}
sum /= 2;

int n = nums.length;
boolean[][] dp = new boolean[n+1][sum+1];
for (int i = 0; i < dp.length; i++) {
Arrays.fill(dp[i], false);
}

dp[0][0] = true;

for (int i = 1; i < n+1; i++) {
dp[i][0] = true;
}
for (int j = 1; j < sum+1; j++) {
dp[0][j] = false;
}

for (int i = 1; i < n+1; i++) {
for (int j = 1; j < sum+1; j++) {
dp[i][j] = dp[i-1][j];
if (j >= nums[i-1]) {
dp[i][j] = (dp[i][j] || dp[i-1][j-nums[i-1]]);
}
}
}

return dp
[sum];
}


改进:

由于每次新状态的更新为仅和i-1的状态有关,因此可以将空间复杂度降为O(n)。注意此时遍历 j 时,需要从后向前;如若从前向后的话,前面更新的值会对后面值的更新产生影响。

bool canPartition(vector<int>& nums) {
int sum = 0;
for(int num: nums) sum += num;
if(sum % 2) return false;
sum /= 2;
bool dp[sum + 1];
fill_n(dp, sum + 1, false);
dp[0] = true;
for(int i = 0; i < nums.size(); i++){
for(int j = sum; j > 0; j--){
if(j >= nums[i]) dp[j] = dp[j] || dp[j - nums[i]];   //not pick || pick
}
}
return dp[sum];
}


Arithmetic Slices

A sequence of number is called arithmetic if it consists of at least three elements and if the difference between any two consecutive elements is the same.

For example, these are arithmetic sequence:
1, 3, 5, 7, 9
7, 7, 7, 7


A slice (P, Q) of array A is called arithmetic if the sequence:

A[P], A[p + 1], ..., A[Q - 1], A[Q] is arithmetic. In particular, this means that P + 1 < Q.

The function should return the number of arithmetic slices in the array A.
不是很困难的一道题。如果A[i] - A[i-1] = lastDiff, 则以A[i]结尾的slice有consecLen - 2 个,所以总的是sliceNum += consecLen - 2。

int numberOfArithmeticSlices(vector<int>& A) {
if(A.size() < 3) return 0;
int consecLen = 2;
int lastDiff = A[1] - A[0];
int sliceNum = 0;
for(int i = 2; i < A.size(); i++){
if(A[i] - A[i-1] == lastDiff){
consecLen++;
sliceNum += consecLen - 2;
}
else{
consecLen = 2;
lastDiff = A[i] - A[i-1];
}
}

a52f
return sliceNum;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode