【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
1since 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 isgas[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; } };
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, givens =
"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问题……
相关文章推荐
- DP17 最少回文切割次数 Palindrome Partitioning @geeksforgeeks
- 分割成回文需要的最小分割数 Palindrome Partitioning II @LeetCode
- LeetCode(Palindrome partition 2) 求将一个字符串划分成回文子串 需要分成的段数最少是多少
- DP之钢管切割,最长回文字符串,最长公共子串
- candy-leetcode :只需要遍历一遍的解法
- LeetCode 140. Word Break II (DP+DFS)
- 最长回文子串 leetcode 05 DP解法
- leetcode--Valid Palindrome--- 算法简单,需要看看怎么写的
- leetcode 132. Palindrome Partitioning II 回文子串 + 深度优先遍历DFS(超时) + 动态规划DP + 这道题需要认真学习
- leetcode 140. Word Break II 深度优先搜索DFS + 很棒的动态规划DP 做法 + 记录前驱节点
- LeetCode-Palindrome Partitioning II-回文分割-DP优化
- 切割回文(区间dp)
- leetcode 50 值得再看一遍
- poj 8471 切割回文(dp+维度压缩)
- Leetcode刷题笔记(部分非原创)(131-140题)
- leetcode 5. Longest Palindromic Substring 最长回文子串的查找 + 按照length做DP
- LeetCode-5-Longest Palindromic Substring 最长回文子串DP
- 简单dp算法——百炼05:切割回文
- leetcode 446. Arithmetic Slices II - Subsequence 等差序列的数量 + 一个很值得学习的DP动态规划做法
- LeetCode 5 Longest Palindromic Substring(最长回文子串,暴力剪枝/DP/曼彻斯特算法)