您的位置:首页 > 其它

【LeetCode131-140】切割回文(值得再看一遍DP),切割词汇(需要看看,DP)

2017-07-03 14:09 351 查看

131.找出所有拆分成回文组合的情况

Given a string s, partition s such that every substring of the partition is a palindrome.

Return all possible palindrome partitioning of s.

For example, given s = 
"aab"
,

Return
[
["aa","b"],
["a","a","b"]
]


迭代一下就好,竟然一点没报错,233…

class Solution {
public:
vector<vector<string>> partition(string s) {
if (s.size() == 0)return vector<vector<string>>();
vector<vector<string>>result;
vector<string>temp;
help(result, temp, s);
return result;
}
void help(vector<vector<string>>&result, vector<string>temp, string s) {
if (s == "") {
result.push_back(temp);
return;
}

for (int i = 0; i < s.size(); ++i) {
if (isPartition(s.substr(0, i + 1))) {
vector<string>temp2(temp.begin(), temp.end());
temp2.push_back(s.substr(0, i+1));
help(result, temp2, s.substr(i+1));
}
}
}
bool isPartition(string s) {
int length = s.size();
for (int i = 0; i <= length / 2; ++i) {
if (s[i] != s[length - i - 1])return false;
}
return true;
}
};


132.切割最短回文块【hard,需要再看看】

Given a string s, partition s such that every substring of the partition is a palindrome.

Return the minimum cuts needed for a palindrome partitioning of s.

For example, given s = 
"aab"
,

Return 
1
 since the palindrome partitioning 
["aa","b"]
 could
be produced using 1 cut.

代码参考了Top Solution...

构建DP挺难的,从后往前,i从n到1,j从i到n...

这么堆上去挺精彩的,而且两个dp可以写到一个循环里

class Solution {
public:
int minCut(string s) {
//比较难想的DP问题!
//保存两两关系的 bool dp[][]  及结果d[]同时起飞
//bool dp[][]从后往前,一段不行之后所有的都不行,这样就避免了迭代带来巨大的工作量
//d[i]代表从i开始到最后需要切割的次数
int n = s.size();
vector<vector<bool>>dp(n, vector<bool>(n, false));
vector<int>d(n+1);
d
= -1;
for (int i = n - 1; i >= 0; --i) {
d[i] = n - i - 1;//最坏的情况
for (int j = i; j <n ; ++j) {
if (s[i] == s[j] && (j - i <= 1 || dp[i + 1][j - 1]))
{
dp[i][j] = true;
d[i] = min(d[i], d[j+1]+1);
}
}
}
return d[0];
}
};


133.无向图的复制(new结构体!!)

关键就是在迭代里要new一下……

struct UndirectedGraphNode {
int label;
vector<UndirectedGraphNode *> neighbors;
UndirectedGraphNode(int x) : label(x) {};
};

class Solution {
public:
UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
if (!node)return nullptr;
unordered_map<int, UndirectedGraphNode *>mapping;
return help(node, mapping);
}
UndirectedGraphNode *help(UndirectedGraphNode *node,
unordered_map<int, UndirectedGraphNode *>&mapping)
{
//这一步是关键!!!
//必须要new出来才不会被析构掉…
mapping[node->label] = new UndirectedGraphNode(node->label);

vector<UndirectedGraphNode *> neighbours;
for (int i = 0; i < node->neighbors.size(); ++i) {
if (mapping[node->neighbors[i]->label])neighbours.push_back(mapping[node->neighbors[i]->label]);
else
neighbours.push_back(help(node->neighbors[i],mapping));
}
mapping[node->label]->neighbors = neighbours;
return mapping[node->label];
}
};


134.选择汽油站【Medium,难想好实现】

There are N gas stations along a circular route, where the amount of gas at station i is 
gas[i]
.

You have a car with an unlimited gas tank and it costs 
cost[i]
 of gas to travel from station i to
its next station (i+1). You begin the journey with an empty tank at one of the gas stations.

Return the starting gas station's index if you can travel around the circuit once, otherwise return -1.

Note:

The solution is guaranteed to be unique.

需要想通两点:

1.总共的油够的话肯定有解

2.遍历一遍保证从第i个到第n个每次油都够,那么第i个肯定是有解的那个解…

class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int total_sum=0;
int result = 0,sum=0;
for (int i = 0; i < gas.size(); ++i)
{
int minus= gas[i] - cost[i];
total_sum += minus;
sum += minus;
if (sum < 0) { result = i + 1; sum = 0; }
}
if (total_sum < 0)return -1;
else return result;
}
};




135.分糖【hard,繁琐,情况多】

There are N children standing in a line. Each child is assigned a rating value.
You are giving candies to these children subjected to the following requirements:
Each child must have at least one candy.
Children with a higher rating get more candies than their neighbors.
What is the minimum candies you must give?

错了十次,击败了98.42%的人………………吓死我了

1.先处理谷底的情况:大--小---大(注意这里的小可以是一行大小一样的)

2.处理完1之后再处理一下首尾即可(先判断首位在1里有没有处理过,如果没有,判断是升还是降,如果一直不降不升就只处理一个)

class Solution {
public:
int candy(vector<int>& ratings) {
if (ratings.size() <= 1)return ratings.size();
int n = ratings.size();
vector<int>result(n, -1);
vector<int>bigger(n - 1);
//1:左大于右   0:相等  -1:左小于右
int max_num = ratings[0];
for (int i = 0; i < n - 1; ++i) {
bigger[i] = (ratings[i] > ratings[i + 1]) ? 1 : ((ratings[i] == ratings[i + 1]) ? 0 : -1);
max_num = max(max_num, ratings[i + 1]);
}
for (int i = 1; i < n - 1; ++i) {
if (bigger[i - 1]==1 ) {//左大于右
int temp2 = 0;
while (bigger[i + temp2] == 0)temp2++;
if (bigger[i + temp2] == -1) {//谷底
for (int a = 0; a < temp2+1;++a)result[i+a] = 1;
//向左
for (int temp = i - 1; temp >= 0; temp--) {
if (bigger[temp] == 1)result[temp] = max(result[temp], result[temp + 1] + 1);
else if (bigger[temp] == 0)result[temp] = max(result[temp], 1);
else break;
}
//向右
for (int temp = i +temp2+ 1; temp < n; temp++) {
if (bigger[temp - 1] == -1)result[temp] = max(result[temp], result[temp - 1] + 1);
else if (bigger[temp-1] == 0)result[temp] = max(result[temp], 1);
else break;
}
}
}
}
if (result[0] == -1 && ratings[0] <= max_num) {
result[0] = 1;
for (int temp = 1; temp < n; temp++) {
if (bigger[temp - 1] == -1)
result[temp] = max(result[temp], result[temp - 1] + 1);
else if (bigger[temp - 1] == 0)
result[temp] = max(result[temp], 1);
else

break;

}
}
if (result.back() == -1 && ratings.back() <max_num) {
result.back() = 1;
for (int temp = n - 2; temp >= 0; temp--) {
if (bigger[temp] == 1)result[temp] = max(result[temp], result[temp + 1] + 1);
else if (bigger[temp] == 0)result[temp] = max(result[temp], 1);
else break;
}
}
int total = 0;
for (int i = 0; i < result.size(); ++i)total += result[i];
return total;
}
};


然后看到了大佬们超级简单的方法:

1.从左到右一次,如果右边大,右边的数字+1

2.从右到左一次,如果左边大,左边的数字=max(左边的数字,右边的数字+1)

求和一下就好…

class Solution {
public:
int candy(vector<int> &ratings)
{
int size=ratings.size();
if(size<=1)
return size;
vector<int> num(size,1);
for (int i = 1; i < size; i++)
{
if(ratings[i]>ratings[i-1])
num[i]=num[i-1]+1;
}
for (int i= size-1; i>0 ; i--)
{
if(ratings[i-1]>ratings[i])
num[i-1]=max(num[i]+1,num[i-1]);
}
int result=0;
for (int i = 0; i < size; i++)
{
result+=num[i];
// cout<<num[i]<<" ";
}
return result;
}
};


136.找出只出现一次的数字【位运算】

Given an array of integers, every element appears twice except for one. Find that single one.
Note:

Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

要求O(n)时间,最好不使用额外空间

然而我用了

class Solution {
public:
int singleNumber(vector<int>& nums) {
unordered_set<int>temp;
for (int i = 0; i < nums.size(); ++i) {
if (temp.find(nums[i]) == temp.end())temp.insert(nums[i]);
else temp.erase(nums[i]);
}
return *temp.begin();
}
};


然后看到了大佬的简洁到令人害怕的代码。。。用^操作符,按位亦或…

class Solution {
public:
int singleNumber(vector<int>& nums) {
int result = nums[0];
for (int i = 1; i < nums.size(); ++i) {
result ^= nums[i];
}

return result;
}
};


137.找出只出现一次的数字2

和上一题类似,这里只有一个数字只出现一次,其他的三次,找出来

然后想了五分钟位运算,还是果断用unordered_set了,用了俩……

class Solution {
public:
int singleNumber(vector<int>& nums) {
unordered_set<int>temp;
unordered_set<int>temp2;
for (int i = 0; i < nums.size(); ++i) {
if (temp.find(nums[i]) == temp.end()) {
if(temp2.find(nums[i]) == temp2.end()){
temp.insert(nums[i]);
temp2.insert(nums[i]);
}
}
else {
temp2.erase(nums[i]);
}

}
return *temp2.begin();
}
};


依然看到大佬的答案,吓死我了…

Challenge me , thx

public int singleNumber(int[] A) {
int ones = 0, twos = 0;
for(int i = 0; i < A.length; i++){
ones = (ones ^ A[i]) & ~twos;
twos = (twos ^ A[i]) & ~ones;
}
return ones;
}


138.复制包换随机指针的链表

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.

Return a deep copy of the list.

这题做得好爽,在VS里写完粘过去稍微改了下就Accept了,23333

1.考虑了next形成环

2.利用了unordered_map...还是之前哪一题看到过这种结构,用起来非常爽

3.先弄完next再random就好了

class Solution {
public:
RandomListNode *copyRandomList(RandomListNode *head) {
if (!head)return nullptr;
unordered_map<RandomListNode *, RandomListNode*>map;
RandomListNode * temp = head;
map[head] = new RandomListNode(head->label);

int length = 1;
while (temp->next) {
if (map.find(temp->next) == map.end()) {//没找到
map[temp->next]= new RandomListNode(temp->next->label);
map[temp]->next = map[temp->next];
temp = temp->next;
length++;
}
else {//形成环了
map[temp]->next = map[temp->next];
}
}
temp = head;
for (int i = 0; i < length; ++i) {
map[temp]->random = temp->random ? map[temp->random] : nullptr;
temp = temp->next;
}
return map[head];
}
};


139.切割词汇【DP,再看看】

看能不能由wordDict里的词汇组成一个string s;

DP !

class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string>list(wordDict.begin(), wordDict.end());
vector<bool>dp(s.size() + 1, false);//dp[i]存储的substring(0,i)是否能被正确切割
dp[0] = true;
for (int i = 1; i < s.size()+1; ++i) {
for (int j = i - 1; j >= 0; --j) {
if (dp[j]) {
if (list.find(s.substr(j, i - j)) != list.end())
dp[i] = true;
}
}
}
return dp.back();

}
};

140.分割词汇2

For example, given
s = 
"catsanddog"
,
dict = 
["cat", "cats", "and", "sand", "dog"]
.

A solution is 
["cats and dog", "cat sand dog"]
.

写了一个和139很类似的DP,发现了TLE,超出限制了

分析原因都是类似于

["aa..(lots of 'a').b", "a","aaaaa"...so on]

的例子

最后参考了  方法  简单的运用上一条的结论,就直接跳出来了……

击败了60%的人

class Solution {
public:
vector<string> wordBreak(string s, vector<string>& wordDict) {
if (!whetherwordBreak(s, wordDict))return {};
unordered_set<string>list(wordDict.begin(), wordDict.end());
vector<vector<string>>dp(s.size() + 1);
dp[0] = { "" };
for (int i = 1; i<s.size() + 1; ++i) {
for (int j = i - 1; j >= 0; --j) {
if (dp[j].size() != 0) {
if (list.count(s.substr(j, i - j)) !=0) {
for (int k = 0; k<dp[j].size(); ++k) {
string temp = dp[j][k];
if (temp.size())temp += " ";
temp += s.substr(j, i - j);
dp[i].push_back(temp);
}
}
}
}
}
return dp.back();
}
bool whetherwordBreak(string s, vector<string>& wordDict) {
unordered_set<string>list(wordDict.begin(), wordDict.end());
vector<bool>dp(s.size() + 1, false);//dp[i]存储的substring(0,i)是否能被正确切割
dp[0] = true;
for (int i = 1; i < s.size() + 1; ++i) {
for (int j = i - 1; j >= 0; --j) {
if (dp[j]) {
if (list.find(s.substr(j, i - j)) != list.end())
dp[i] = true;
}
}
}
return dp.back();

}

};

一堆DP问题……

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