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[n] = -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;
}
};
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();
}
};
依然看到大佬的答案,吓死我了…
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问题……