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


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;
 }
};


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();
	}
};



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

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问题……








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朱铭德

五毛也是爱٩(●´৺`●)૭

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值