找题用ctrl+f来找。做到这里开始有点扛不住了。。有些算法是百度的,面试的话应该用不到那么复杂的算法,以后有时间再补吧。
1.Remove Duplicates from Sorted List II
题目意思:去除排序链表中所有有重复的元素,一个不留.
这题比较简单,估计就是指针操作想不清楚吧。就是要注意这一题是把所有重复的点都去掉。
class Solution {
public:
ListNode *deleteDuplicates(ListNode *head) {
if( head == NULL) return NULL;
if( head ->next == NULL) return head;
ListNode *ans = NULL;
ListNode *tail = NULL;
while(head){
if( head->next && head->val == head->next->val){
ListNode *temp ;
if(head->next->next && head->next->val == head->next->next->val){
temp = head->next;
free(head);
head = temp;
} else {
temp = head->next->next;
free(head->next);
free(head);
head = temp;
}
} else {
if( ans == NULL){
ans = tail = head;
} else {
tail->next = head;
tail = tail->next;
}
head = head->next;
tail -> next = NULL;
}
}
return ans;
}
};
题目意思:把链表的前k个节点一组反序.
感觉这后面ac率低的都是和指针相关的题目。。这题开始我以为是把前K个反序。。结果是按K个一组来反序。直接递归就好。
class Solution {
public:
ListNode *reverseKGroup(ListNode *head, int k) {
if (head == NULL || head->next == NULL||k<=1) return head;
int len = 0;
ListNode *ans = head;
while (ans)
{
len++;
ans = ans->next;
}
if (k > len) return head;
ListNode *cur = head;
ans = NULL;
int cnt = k;
while (cur && cnt > 0)
{
ListNode *temp = cur->next;
cur->next = ans;
ans = cur;
cur = temp;
cnt--;
}
if (len - k >= k)
head->next = reverseKGroup(cur,k);
else
head->next = cur;
return ans;
}
};
题目意思:判断T是否是S的顺序字串.顺序字串的意思就是T中的字符和S中出现的顺序一致.
这题看着直接递归可以做,但是S的串太长了,我交了直接超时。。。。只好动态规划了。思路:一行一行的刷数值,每个点存入当前t[j]和之前的字符在s[i]及其之前出现的次数。。如果两个值不等,那么当前值和前一个s[i - 1][j]相等;如果两个值相等,那么dp[i][j] =dp[i-1][j] + dp[i-1][j-1],即当前s中的字符加入前和之前从i-1累计起来的和。
class Solution {
public:
int numDistinct(string S, string T) {
int s_size = S.size();
int t_size = T.size();
if( t_size == 0 || t_size > s_size) return 0;
vector<vector<int> > dp(s_size + 1, vector<int>(t_size + 1, 0));
for(int i = 0 ; i <= s_size ; i++) dp[i][0] = 1;
for(int i = 1 ; i <= s_size ; i ++){
for(int j = 1 ; j <= t_size ; j++){
dp[i][j] = dp[i - 1][j];
if( S[i - 1] == T[j - 1])
dp[i][j] += dp[i - 1][j - 1];
}
}
return dp[s_size][t_size];
}
};
4. Jump Game II
题目意思:给一个数组,其中保存可以跳跃的长度,返回最早可以跳到末尾的步数.
这个就和之前的判断能否跳到最后差不多,我就是在这上面改的。但是改了好久。。边界条件和特殊情况不容易想清楚。特别是{1,1,1,1}这种情况要注意。i一定得从0开始,否则就过不了。而且返回的是最小步数不是题目说的index啊.......
class Solution {
public:
int jump(int A[], int n) {
if( A == NULL) return 0;
if( n == 1) return 0;
if( A[0] >= n - 1) return 1;
int max_index = A[0];
int cnt = 1;
bool flag;
for(int i = 0 ; i <= max_index && max_index < n - 1; i++){
flag = false;
int update;
for(int j = 1 ; j <= A[i] ; j++){
if( max_index < (i + j + A[i + j])){
max_index = i + j + A[i + j], flag = true;
update = i + j;
}
}
if(flag){
cnt++;
if( max_index >= n -1) return cnt ;
i = update - 1;
}
}
return -1;
}
};
题目意思:从num数组中找出几个数能够组合成target.并且每个数字只能取一次,但是可能有重复元素.但结果中不能有重复数组.
这一题和之前题一样,可以用DFS做。只是因为可以有重复的值,所以得改一下。
class Solution {
public:
vector<vector<int> > answer;
vector<int> temp;
vector<vector<int> > combinationSum2(vector<int> &num, int target) {
sort(num.begin(), num.end());
int size = num.size() - 1;
while(num[size] > target) size --;
if( size < 0 ) return answer;
DFS(num, size, target);
return answer;
}
void DFS(vector<int> &num, int size, int target){
if (target < 0) return;
int pre = num[size];
for(int i = size ; i >= 0 ; i --){
if( i!= size && pre == num[i])
continue;
if(num[i] <= target){
temp.push_back(num[i]);
if( target == num[i]){
answer.push_back(vector<int> (temp.rbegin(), temp.rend()));
} else {
DFS(num, i - 1, target - num[i]);
}
temp.pop_back();
}
pre = num[i];
}
}
};
题目意思:将单词按下面的样子排序一共nRows列.
P A H N A P L S I I G Y I R
Z字形重组字符。。我感觉应该是N。。相当于一直在画一个斜着的v字。每次一行行的加入,可以用公式算出来。关键是oj提示。。开始把步长公式写成了base_walk = nRows + nRows / 2;了。。。但OJ提示runtime error。。。搞得我还以为是我string的操作错了。。。
class Solution {
public:
string convert(string s, int nRows) {
int size = s.size();
if( nRows >= size ) return s;
string ans = "";
int base_walk;
if( nRows > 2 ) base_walk = nRows + nRows - 2;
else base_walk = nRows;
for(int i = 0 ; i < nRows ;i++){
int walk = base_walk - 2 * i;
if( !walk ) walk = base_walk;
int cur = i;
if( walk != base_walk ){
while(cur < size){
ans += s[cur];
cur += walk;
walk = base_walk - walk;
}
} else {
while(cur < size){
ans += s[cur];
cur += walk;
}
}
}
return ans;
}
};
7.Anagrams
题目意思:在其中查找有哪些回文构词的词.即两个单词,词中的字符类型和数目都一样,只是顺序不同.
这一题就是说这些串中,字符类型和数目一致的串有哪些。开始的时候我准备用一个vector<vector<char>>来存储统计数字的。虽说效率不错,但是那样写起来好麻烦,要自己写统计,判断和查找过程。在网上搜了个答案,和我思路差不多。都是先映射,然后再找,然后再添加的过程。
我就把思路清晰的代码挂上来吧。
class Solution {
public:
vector<string> anagrams(vector<string> &strs) {
map<string, int> my_map;
vector<string> ans;
map<string, int>::iterator checkin;
int size = strs.size();
for(int i = 0 ; i < size ; i++){
string temp = strs[i];
sort(temp.begin(), temp.end());
checkin = my_map.find(temp);
if( checkin == my_map.end() ){
my_map[temp] = i;
} else {
if( my_map[temp] == -1){
ans.push_back(strs[i]);
} else {
ans.push_back(strs[my_map[temp]]);
my_map[temp] = -1;
ans.push_back(strs[i]);
}
}
}
return ans;
}
};
题目意思:二叉搜索树中有两个点被交换了,恢复成原样.
这一题最简单的就是遍历然后一个个的存入结点了。再就是中序遍历,找出两个不和谐的点,其值交换。感觉中序遍历应该也算是log(n)的空间,不算常量。。百度后发现还有morris travel这个东西,感觉就是生成线索树,然后再遍历。。当然线索树的实现也有很多种,morris travel应该是最优的吧。为了简单,我还是写中序遍历的方法吧。
class Solution {
public:
TreeNode *a;
TreeNode *b;
TreeNode *pre;
void recoverTree(TreeNode *root) {
if( root == NULL ) return;
a = b = NULL;
pre = NULL;
DFS(root);
if( a ){
int temp = a->val;
a->val = b->val;
b->val = temp;
}
}
void DFS(TreeNode *root){
if(root == NULL) return;
DFS(root->left);
if(pre && pre->val > root->val){
if( a == NULL){
a = pre;
b = root;
} else {
b = root;
}
}
pre = root;
DFS(root->right);
}
};
9.Copy List with Random Pointer
题目意思:链表的每个节点有一个随机指向其余节点的指针.复制这个链表.
这一题在书上看到过。简单来说,就是把每个结点的复制直接插在后面。就是要注意,最后要把生成的链表取出来,然后还原原链表。
class Solution {
public:
RandomListNode *copyRandomList(RandomListNode *head) {
if( head == NULL) return NULL;
RandomListNode * cur = head;
RandomListNode *pre;
while(cur){
pre = cur;
cur = cur->next;
pre->next = new RandomListNode(pre->label);
pre = pre->next;
pre->next = cur;
}
cur = head;
while(cur){
pre = cur;
cur = cur->next->next;
if( pre->random ){
pre->next->random = pre->random->next;
}
}
cur = head->next->next;
RandomListNode * ans = head->next;
RandomListNode * ans_tail = head->next;
head->next = head->next->next;
while(cur){
pre = cur;
cur = cur->next->next;
ans_tail->next = pre->next;
ans_tail = ans_tail->next;
pre->next = cur;
}
pre->next = NULL;
return ans;
}
};
题目意思:链表存储两个数,每个节点存储一位,然后返回两个链表相加的和的链表.
这个就是大数加法~反正三个循环就OK。
class Solution {
public:
ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
if( l1 == NULL && l2 == NULL) return NULL;
if( l1 == NULL ) return l2;
if( l2 == NULL ) return l1;
ListNode *ans;
ListNode *tail;
int val = l1->val + l2->val;
int up = val / 10;
val = val % 10;
ans = tail = new ListNode(val);
tail->next = NULL;
l1 = l1->next;
l2 = l2->next;
while(l1 && l2){
val = l1->val + l2->val + up ;
up = val / 10;
val = val % 10;
tail->next = new ListNode(val);
tail = tail->next;
tail->next = NULL;
l1 = l1->next;
l2 = l2->next;
}
while(l1){
val = l1->val + up;
up = val / 10;
val = val % 10;
tail->next = new ListNode(val);
tail = tail->next;
tail->next = NULL;
l1 = l1->next;
}
while(l2){
val = l2->val + up;
up = val / 10;
val = val % 10;
tail->next = new ListNode(val);
tail = tail->next;
tail->next = NULL;
l2 = l2->next;
}
if( up ){
tail->next = new ListNode(up);
tail->next->next = NULL;
}
return ans;
}
};
题目意思:判断一个字符串是否回文,只判断大小写字母和数字.
这一题好简单。。就是注意,大小写字母可以对应上,数字也可以对应。
class Solution {
public:
bool isPalindrome(string s) {
int size = s.size();
string temp;
int i = 0 ;
while(i < size ){
if( s[i] >= 'a' && s[i] <= 'z' || s[i] >= 'A' && s[i] <= 'Z' || s[i] >= '0' && s[i] <= '9'){
if(s[i] >= 'A' && s[i] <= 'Z') temp.push_back(s[i]);
else temp.push_back(s[i]-('a'-'A'));
}
i++;
}
size = temp.size() - 1;
for(int i = 0 ; i <= size/2 ; i++){
if( temp[i] != temp[size - i])
return false;
}
return true;
}
};
12.Clone Graph
题目意思:复制一个无向图.{0,1,2#1,2#2,2}
.表示有0,1两个点,并且2和1有一条线,2#2有一条线.
总算看到图论的题目了。。这么长的类型名字还是看不习惯。。思路就是直接广搜遍历一遍图按值创建结点,然后再遍历一边设置其连接。有map还是方便多了,原来只会C的时候写映射真叫一个痛苦啊。。。
/**
* Definition for undirected graph.
* struct UndirectedGraphNode {
* int label;
* vector<UndirectedGraphNode *> neighbors;
* UndirectedGraphNode(int x) : label(x) {};
* };
*/
class Solution {
public:
UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
if( node == NULL ) return NULL;
map<int, UndirectedGraphNode *> my_map;
queue<UndirectedGraphNode *> my_queue;
my_queue.push(node);
while( !my_queue.empty()){
UndirectedGraphNode * temp = my_queue.front();
if(my_map.find(temp->label) == my_map.end()){
UndirectedGraphNode* new_node = new UndirectedGraphNode(temp->label);
my_map.insert(pair<int, UndirectedGraphNode*>(new_node->label, new_node));
int size = temp->neighbors.size();
for(int i = 0 ; i < size ; i++){
my_queue.push(temp->neighbors[i]);
}
}
my_queue.pop();
}
my_queue.push(node);
while( !my_queue.empty()){
UndirectedGraphNode *temp = my_queue.front();
UndirectedGraphNode *cur = my_map[temp->label];
if(cur->neighbors.empty() && !temp->neighbors.empty()){
int size = temp->neighbors.size();
for(int i = 0;i < size; i++)
{
cur->neighbors.push_back(my_map[temp->neighbors[i]->label]);
my_queue.push(temp->neighbors[i]);
}
}
my_queue.pop();
}
return my_map[node->label];
}
};
题目意思:找到数组中第一个欠缺的不连续的值.
这题开始感觉用不到额外空间啊。。直接循环一遍筛值累加,记录最小值和最大值,然后公式一算,和之前的和一减就得结果了。。提交了才发现至少从1开始看有没有空,而且还有重复的元素。。就不能用和来算了。。搜了一下算法,原来还可以把对应的索引与值联系起来的方式来做。思路就是,i从0开始,针对每一个A[i],如果不等于i + 1那么就证明这个点可交换,然后向其值为下标的地方交换。当然,这里的下标为其值减一。如果下标不合法,那么表明这个点不可用其值交换,则i++到下一个点继续交换。
class Solution {
public:
int firstMissingPositive(int A[], int n) {
if( A == NULL || n <= 0) return 1;
int i;
for(i = 0 ; i < n ; i++){
while(A[i] != i + 1){
if (A[i] <= 0 || A[i] >= n || A[i] == A[A[i] - 1]) break;
swap(A[i], A[A[i] - 1]);
}
}
i = 1;
while( i <= n && A[i - 1] == i ) i++;
return i;
}
};
-14.Scramble String
题目意思:给两个字符串,判断他们是否攀登串.即一个串被分解成二叉树形式,可以通过转换子节点来变成另外一个串.
这一题开始就想到枚举了。感觉效率好低。。就网上搜答案,比较好的思路是动态规划。不过我没看太懂。。。自己写就DFS枚举分串了。MD。。这题对照着百度搜的答案对了半天。。尼玛set验证循环的时候我写成了i<size。。。害我改半天。。。
class Solution {
public:
bool isScramble(string s1, string s2) {
int size = s1.size();
if( size != s1.size() ) return false;
if( s1 == s2) return true;
int set[26];
memset(set, 0, sizeof(int)*26);
for(int i = 0 ; i < size ; i++){
set[s1[i] - 'a']++;
set[s2[i] - 'a']--;
}
for(int i = 0 ; i < 26 ; i++)
if(set[i] != 0) return false;
bool ans;
for(int i = 1 ;i < size ;i++){
ans = isScramble(s1.substr(0, i), s2.substr(0, i)) && isScramble(s1.substr(i), s2.substr(i));
if( ans ) return ans;
ans = isScramble(s1.substr(0, i), s2.substr(size - i, i)) && isScramble(s1.substr(i) , s2.substr(0 , size - i));
if( ans ) return ans;
}
return false;
}
};
-15.Best Time to Buy and Sell Stock III
题目意思:给出股票每天的价格表,求出卖一次再买一次的最大利润
刷了100题后,感觉越来越难刷了啊。。。这题的意思我一开始还没搞懂。。以为是一天最多一卖一买。实际上是只能卖一次,买一次,而且卖得在买前。思路参考的http://blog.youkuaiyun.com/pickless/article/details/12034365
感觉他写的很清楚了。我自己也仿照着写了一遍。思路相当于是把他说的第一种思路优化之后的结果,也就是
class Solution {
public:
int maxProfit(vector<int> &prices) {
int profit = 0;
int size = prices.size();
if (size == 0) return 0;
int left[size];
int right[size];
memset(left, 0, sizeof(int) * size);
memset(right, 0, sizeof(int) * size);
int min_val = prices[0];
for (int i = 1; i < size; i++) {
left[i] = max(prices[i] - min_val, left[i - 1]);
min_val = min(prices[i], min_val);
}
int max_val = prices[size - 1];
for (int i = size - 2; i >= 0; i--) {
right[i] = max(max_val - prices[i], right[i + 1]);
max_val = max(prices[i], max_val);
}
for (int i = 0; i < size; i++) {
profit = max(left[i] + right[i], profit);
}
return profit;
}
inline int max(int a,int b){
return a > b ? a : b;
}
inline int min(int a,int b){
return a < b ? a : b;
}
};
16.Longest Substring Without Repeating Characters
题目意思:找到没有重复元素的最长字符串,并且返回其长度.
这一题感觉还比较简单吧。因为是求最长子串的长度,而不是字串的长度,所以比较简单。最直接的思路就是两个循环然后判断是否有重复了。但那样效率太低。所以就用两个指针变量,一个指向开头,一个指向当前。需要注意的就是必须以将-1填充flag并且以-1为起点。不然的话,最长字串在开头就会少少一。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int size = s.size();
int flag[256];
memset(flag, -1, sizeof(flag));
int start = -1;
int max = 0;
for(int i = 0; i < size ; i++){
if(flag[s[i]] > start){
start = flag[s[i]];
}
flag[s[i]] = i;
max = (max > i - start ? max : i - start );
}
return max;
}
};
-17.Sqrt(x)
题目意思:求x开方
这题看着直接用二分很简单,但其实细节位置很容易错!比如说溢出和最后的返回值。我开始用double判断差绝对值小于1e-6不知道为什么一直死循环。。然后发现返回值是int。。又用int。。结果1和0不好过。。干脆再开头写个判断。。后来又mid*mid对大输入会溢出。。所以只好用除法了。。。
class Solution {
public:
int sqrt(int x) {
if(x <= 1) return x;
int left = 0;
int right = x;
int mid;
int temp;
while (left <= right)
{
mid = ( left + right) / 2;
int cur = x / mid;
if ( cur > mid ) left = mid + 1;
else if ( cur < mid ) right = mid - 1;
else return mid;
}
if( x < mid * mid) return mid - 1;
else return mid;
}
};
题目意思:求从1...n的串的全排列结果中的第k个.
这一题直接用之前那个得到下一个序列的方法就行了。我搜了一下,还可以按位算排列组合的个数。然后得出结果。我就贴我自己的代码好了。。
class Solution {
public:
string getPermutation(int n, int k) {
string ans;
for(int i = 1; i <= n ; i++){
ans.push_back(i + '0');
}
for(int i = 1 ; i < k ; i++){
nextPermutation(ans);
}
return ans;
}
void nextPermutation(string &num) {
int size = num.size() - 1;
int len = size;
size --;
while( size >= 0){
if( num[size] >= num[size + 1])
size--;
else break;
}
if( size < 0) reverse(num, 0, len);
else{
int gmin = size;
for(int i = len;i >=0 ;i--){
if( num[size] < num[i] ){
gmin = i;
break;
}
}
swap(num[gmin], num[size]);
reverse(num, size + 1, len);
}
}
void swap(char &a,char &b){
int temp = a;
a = b;
b = temp;
}
void reverse(string &num, int start, int end){
if( start == end ) return;
int min = (start + end) / 2;
for(int i = start ; i <= min ; i ++){
swap(num[i], num[start + end - i]);
}
}
};
19.Rotate List
题目意思: 和循环数组类似的链表.也就是说将倒数k个节点插入到链表头.
这一题也是设置一快一慢指针的题目。但是这一题k有可能大于表长。。。所以,如果k是表长的倍数,那么直接返回head。否则还要重新循环一遍。
class Solution {
public:
ListNode *rotateRight(ListNode *head, int k) {
if( head == NULL ) return NULL;
ListNode *ans;
ListNode *fast = head;
ListNode *slow = head;
int cnt = 1;
while(fast->next){
fast = fast->next;
cnt++;
}
if(k >= cnt && k % cnt == 0) return head;
int temp = k % cnt;
fast = head;
while(fast->next){
fast = fast->next;
if(temp == 0) slow = slow->next;
else temp --;
}
fast->next = head;
ans = slow->next;
slow->next = NULL;
return ans;
}
};
20. Merge k Sorted Lists
题目意思:合并k个已经排序的链表.
这题。。两两合并超时。。。仔细一想时间复杂度是n^2。并且n是所有链表的长度。。。所以只好换方法了。。。思路就是每次从这些表的表头取出最小的值插入。优先队列做的。每次取出节点后,将其地址的下一个值插入堆中,每次从优先队列中取就行了。时间复杂度基本就是n了。
typedef struct my_node{
int val;
int pos;
friend bool operator < (my_node n1, my_node n2){
return n1.val > n2.val;
}
}my_node;
class Solution {
public:
ListNode *mergeKLists(vector<ListNode *> &lists) {
int size = lists.size();
if(size == 0 ) return NULL;
ListNode *ans = NULL;
ListNode *tail;
priority_queue<my_node> heap;
my_node temp;
for(int i = 0 ; i < size ; i++){
if( lists[i] == NULL ) continue;
temp.val = lists[i]->val;
temp.pos = i;
heap.push(temp);
}
while( !heap.empty()){
temp = heap.top();
heap.pop();
if(ans == NULL ){
ans = tail = lists[temp.pos];
} else {
tail->next = lists[temp.pos];
tail = tail->next;
}
lists[temp.pos] = lists[temp.pos]->next;
if( lists[temp.pos] == NULL ) continue;
temp.val = lists[temp.pos]->val;
heap.push(temp);
}
return ans;
}
};
题目意思:实现在haystack中找到needle第一次出现的下标地址.
感觉这题是要写kmp算法。。我个人不是很想写。。结果写了个穷举的没想到过了。。。反正string的find就是用的kmp,思路就是对匹配的串进行计算,然后根据计算结果去智能匹配。
class Solution {
public:
char *strStr(char *haystack, char *needle) {
int s1 = strlen(haystack);
int s2 = strlen(needle);
if( s2 == 0 ) return haystack;
if( s2 > s1 ) return NULL;
for(int i = 0 ; i <= s1 - s2 ;i++){
int j;
for(j = 0 ; j < s2 - 1 ;j++){
if(haystack[i + j] != needle[j])
break;
}
if(haystack[i + j] == needle[j])
return haystack + i;
}
return NULL;
}
};
-22.Largest Rectangle in Histogram
题目意思:找到最大的面积.和水池那题有点像.
开始我想的是n^2的循环法。。。当然超时了。。想来想去从,肯定是用区间内最小值乘以长度来判断。搜了一下,思路是用栈,栈中保存递增的下标。遇到值比栈顶元素大则入站,否则从栈中弹出元素,看能围成的最大面积。
class Solution {
public:
int largestRectangleArea(vector<int> &height) {
height.push_back(0);
int size = height.size();
stack<int> my_stack;
int answer = 0;
for(int i = 0 ; i < size;){
if( my_stack.empty() || height[my_stack.top()] <= height[i]){
my_stack.push(i);
i++;
}
else {
int temp = my_stack.top();
my_stack.pop();
int area = max(answer, height[temp] * (my_stack.empty() ? i : i - my_stack.top() - 1));
if( answer < area) answer = area;
}
}
height.pop_back();
return answer;
}
};
刚开始我还纳闷, 为什么是乘height[temp]。仔细一想,如果当前值一直小于栈顶值,那么会一直出栈到刚好最小的值处。由于栈中存储的下标是递增的,所以栈底元素到栈顶之前,必然是可以直接乘以距离的,即中间没有比其小的元素。故这种解法成立。
--23. Maximal Rectangle
题目意思:矩阵被0和1给填充.在矩阵中找到最大的全是1的矩阵.
这题感觉没说清楚,是区域中1的和才对。对题目也没什么感觉。。。。感觉只能用4层循环来写。。。搜了一下,思路就是先纵向处理,把每个位置的值表示为从这一列上面不为0的地方开始向下计数。就成了直方图。然后就和上一题差不多了。通过直方图来统计其和。但这些个矩形的起点不一样,所以只好一层层的来合并求最大值了。
class Solution {
public:
int largestRectangleArea(vector<int> &height) {
height.push_back(0);
int size = height.size();
stack<int> my_stack;
int answer = 0;
for(int i = 0 ; i < size;){
if( my_stack.empty() || height[my_stack.top()] <= height[i]){
my_stack.push(i);
i++;
}
else {
int temp = my_stack.top();
my_stack.pop();
int area = max(answer, height[temp] * (my_stack.empty() ? i : i - my_stack.top() - 1));
if( answer < area) answer = area;
}
}
height.pop_back();
return answer;
}
int maximalRectangle(vector<vector<char> > &matrix) {
int n = matrix.size();
if (matrix.size() < 1) return 0;
int m = matrix[0].size();
if (m < 1) return 0;
vector<vector<int> > lines(n, vector<int>(m, 0));
for (int j = 0; j < m; j++)
lines[0][j] = ((matrix[0][j] == '1') ? 1 : 0);
for (int i = 1; i < n; ++i) {
for (int j = 0; j < m; ++j) {
lines[i][j] += ((matrix[i][j] == '1') ? lines[i-1][j] + 1 : 0);
}
}
int answer = 0;
for (int i = 0; i < n; ++i) {
int temp = largestRectangleArea(lines[i]);
answer = max(answer, temp);
}
return answer;
}
};
题目意思:找出9*9的一个解决方案.
这题直接递归就好了。我开始传递3个二维数组超时了。。。。仔细一想,因为参数过多,栈调用太频繁造成的。。。改了一下,发现还有问题。。。。。主要在于对于b_flags。其地址应该是i/3*3 + j。。而我开始写的就是i/3…大家也要注意。。
class Solution {
public:
vector<vector<bool> > r_flags;
vector<vector<bool> > c_flags;
vector<vector<bool> > b_flags;
void solveSudoku(vector<vector<char> > &board) {
for(int i = 0 ; i < 9 ;i++){
r_flags.push_back(vector<bool>(10, false));
c_flags.push_back(vector<bool>(10, false));
b_flags.push_back(vector<bool>(10, false));
}
for(int i = 0 ; i < 9 ;i++){
for(int j = 0 ; j < 9 ; j++){
if(board[i][j] != '.'){
int temp = board[i][j] - '1';
r_flags[i][ temp ] = true;
c_flags[j][ temp ] = true;
b_flags[i/3*3 + j / 3][temp] = true;
}
}
}
DFS(board);
}
bool DFS(vector<vector<char> > &board){
for(int i = 0 ; i < 9; i++){
for(int j = 0; j < 9 ;j++){
if( board[i][j] == '.'){
for(int k = 0 ; k < 9 ;k++){
if(r_flags[i][k] == false && c_flags[j][k] == false && b_flags[i/3*3 + j / 3][k] == false){
r_flags[i][k] = true;
c_flags[j][k] = true;
b_flags[i/3*3 + j / 3][k] = true;
board[i][j] = k + '1';
if(DFS(board)) return true;
board[i][j] = '.';
r_flags[i][k] = false;
c_flags[j][k] = false;
b_flags[i/3*3 + j / 3][k] = false;
}
}
return false;
}
}
}
return true;
}
};
25.4Sum
题目意思:找出数组中的4个数的和为target的所有组合.
这一题在之前做过一道类似的。可以用它的思路,三层循环。头两层是头两个数,最后一个循环用逼近。结果错了。。。因为这题有重复元素,并且是返回集合,所以很有可能结果中也有重复元素。。改也不好改,遇到重复元素就跳过也不行,毕竟有的答案就是有重复元素的,不跳也不行。。百度了一下,发现可以用set。。。我就用set好了,这也是第一次用set。
class Solution {
public:
vector<vector<int> > fourSum(vector<int> &num, int target) {
vector<vector<int> > answer;
set<vector<int> > set_ans;
sort(num.begin(), num.end());
int size = num.size();
for(int i = 0 ; i < size; i++){
int pre = num[i];
for(int j = i + 1 ; j < size ; j++){
int start = j + 1;
int end = size - 1;
while(start < end){
int sum = num[i] + num[j] + num[start] + num[end];
if( sum == target){
vector<int> temp;
temp.push_back(num[i]);
temp.push_back(num[j]);
temp.push_back(num[start]);
temp.push_back(num[end]);
set_ans.insert(temp);
start++;
}
else if( sum < target) start ++;
else end--;
}
}
}
for(auto i : set_ans)
answer.push_back(i);
return answer;
}
};
26.Word Break
题目意思: 可以从dict中找出单词凑成s.
这一题开始就觉得直接两个for循环就好了,当然超时了。。。搜了一记,原来是动态规划的题目。思路就是顺次判断,dp表示当前结点之前的结点是否可分解。如果当前结点可分解,那么继续分解后面的内容。否则,寻找下一个可分解的位置。
class Solution {
public:
bool wordBreak(string s, unordered_set<string> &dict) {
int size = s.size();
vector<bool> dp(size + 1, false);
dp[0] = true;
for(int i = 1;i <= size;i++){
if(dp[i - 1]){
int start = i - 1;
for(int j = start;j < size;j++){
string cur = s.substr(start, j - start + 1);
if(dict.count(cur) > 0)
dp[j + 1] = true;
}
}
}
return dp[size];
}
};
题目意思:合并区间,即数组中的区间有可能会相交,合并这些相邻的有交集的区间.
这一题直接排个序,然后O(n)合并即可。头一次给sort添加排序函数,发现不能写在class内。所以没办法,只能放在外面了。
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
bool cmp(Interval a,Interval b){
if( a.start < b.start )
return true;
if( a.start == b.start)
return a.end < b.end;
return false;
}
class Solution {
public:
vector<Interval> merge(vector<Interval> &intervals) {
vector<Interval> answer;
int size = intervals.size();
if( size < 1) return answer;
sort(intervals.begin(), intervals.end(), cmp);
int begin = 0;
answer.push_back(intervals[0]);
for(int i = 1 ; i < size ; i++){
Interval temp = answer.back();
if( temp.start == intervals[i].start){
if( temp.end >= intervals[i].end) continue;
answer.pop_back();
answer.push_back(intervals[i]);
} else if( temp.end >= intervals[i].start){
if( temp.end < intervals[i].end){
answer.pop_back();
temp.end = intervals[i].end;
answer.push_back(temp);
}
} else {
answer.push_back(intervals[i]);
}
}
return answer;
}
};
28.Longest Palindromic Substring
题目意思:找出s的最长回文字串..S长度不超过1000
题目最长回文子串。这题我直接穷举每个中间点就做出来了。。。耗时212ms,复制了一个动态规划的代码反而跑了688ms。。。。。又复制了一个O(n)的,运行48ms。。
class Solution {
public:
string longestPalindrome(string s) {
int size = s.size();
if(size <= 1) return s;
int start = -1;
int length = -1;
for(int i = 1 ; i < size ; i++){
int left = i - 1;
int right = i + 1;
int len;
while(left >= 0 && right < size && s[left] == s[right]){
len = right - left + 1;
if(len > length){
length = len;
start = left;
}
left--;
right ++;
}
left = i - 1;
right = i;
while(left >= 0 && right < size && s[left] == s[right]){
len = right - left + 1;
if(len > length){
length = len;
start = left;
}
left--;
right ++;
}
}
string ans;
if( start == -1 ) ans = "";
else ans = s.substr(start, length);
return ans;
}
};
29. Insert Interval
题目意思: 向一个已经对区间排序的数组中插入一个区间,并且合并所有可以合并的区间
这题直接用上面的合并就好了。先插入,后合并。
class Solution {
public:
vector<Interval> insert(vector<Interval> &intervals, Interval newInterval) {
vector<Interval> answer;
int size = intervals.size();
if( size == 0){
answer.push_back(newInterval);
return answer;
}
int i;
for(i = 0 ; i < size ;i++){
if( intervals[i].start < newInterval.start)
answer.push_back(intervals[i]);
else break;
}
answer.push_back(newInterval);
for(; i < size ; i++)
answer.push_back(intervals[i]);
return merge(answer);
}
vector<Interval> merge(vector<Interval> &intervals) {
vector<Interval> answer;
int size = intervals.size();
if( size < 1) return answer;
answer.push_back(intervals[0]);
for(int i = 1 ; i < size ; i++){
Interval temp = answer.back();
if( temp.start == intervals[i].start){
if( temp.end >= intervals[i].end) continue;
answer.pop_back();
answer.push_back(intervals[i]);
} else if( temp.end >= intervals[i].start){
if( temp.end < intervals[i].end){
answer.pop_back();
temp.end = intervals[i].end;
answer.push_back(temp);
}
} else {
answer.push_back(intervals[i]);
}
}
return answer;
}
};
题目意思:用两个数字字符串做乘法,得到一个结果数字串.
这次最后来了道大数乘法。。。做的时间比较晚。。。调试了一个小时。。。。。。。。。。思路就是模拟手算。好久没有做字符串了,感觉还是很多细节要注意啊。。。
class Solution {
public:
string multiply(string num1, string num2) {
int s1 = num1.size();
int s2 = num2.size();
vector<int> ans(s1 + s2, 0);
if( !s1 || !s2 ) return "";
if( s1 == 1 && num1[0] == '0' || s2 == 1 && num2[0] == '0')
return "0";
if( s2 > s1 ){
string temp = num1;
num1 = num2;
num2 = temp;
int t = s1;
s1 = s2;
s2 = t;
}
s1--,s2--;
int cur ;
for(int i = s2 ;i >= 0 ;i--){
int a = num2[i] - '0';
cur = s1 + i + 1;
for(int j = s1 ;j >= 0; j--, cur--){
int b = num1[j] - '0';
int t = a * b;
ans[cur] += t;
}
}
for(int i = s1 + s2 + 1; i >= 1;i--){
ans[i - 1] += ans[i]/10;
ans[i] %= 10;
}
int i = 0;
while(ans[i] == 0) i++;
string answer(s1 + s2 + 2, '0');
int start = i;
while(i < s1 + s2 + 2){
answer[i] += ans[i];
i++;
}
return answer.substr(start);
}
};