leetcode题目思路以及部分解答(四)

找题用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;
    }
};

2.Reverse Nodes in k-Group

题目意思:把链表的前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;
    }
};

3.Distinct Subsequences

题目意思:判断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

题目意思:给一个数组,其中保存可以跳跃的长度,返回最早可以跳到末尾的步数.

这个就和之前的判断能否跳到最后差不多,我就是在这上面改的。但是改了好久。。边界条件和特殊情况不容易想清楚。特别是{1111}这种情况要注意。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;
    }
};

5.Combination Sum II

题目意思:从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];
        }
    }
};

6.ZigZag Conversion

题目意思:将单词按下面的样子排序一共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;
    }
};

-8.Recover Binary Search Tree

题目意思:二叉搜索树中有两个点被交换了,恢复成原样.

这一题最简单的就是遍历然后一个个的存入结点了。再就是中序遍历,找出两个不和谐的点,其值交换。感觉中序遍历应该也算是logn)的空间,不算常量。。百度后发现还有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;
    }
};

10.Add Two Numbers

题目意思:链表存储两个数,每个节点存储一位,然后返回两个链表相加的和的链表.

这个就是大数加法~反正三个循环就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;
    }
};

11.Valid Palindrome

题目意思:判断一个字符串是否回文,只判断大小写字母和数字.

这一题好简单。。就是注意,大小写字母可以对应上,数字也可以对应。

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

-13.First Missing Positive

题目意思:找到数组中第一个欠缺的不连续的值.

这题开始感觉用不到额外空间啊。。直接循环一遍筛值累加,记录最小值和最大值,然后公式一算,和之前的和一减就得结果了。。提交了才发现至少从1开始看有没有空,而且还有重复的元素。。就不能用和来算了。。搜了一下算法,原来还可以把对应的索引与值联系起来的方式来做。思路就是,i0开始,针对每一个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。。结果10不好过。。干脆再开头写个判断。。后来又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;
	}
};

18.Permutation Sequence

题目意思:求从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;
    }
};

21.Implement strStr()

题目意思:实现在haystack中找到needle第一次出现的下标地址.

感觉这题是要写kmp算法。。我个人不是很想写。。结果写了个穷举的没想到过了。。。反正stringfind就是用的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;
    }
};

24.Sudoku Solver

题目意思:找出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];
	}
};

27.Merge Intervals

题目意思:合并区间,即数组中的区间有可能会相交,合并这些相邻的有交集的区间.

这一题直接排个序,然后On)合并即可。头一次给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;
    }
};

30.Multiply Strings

题目意思:用两个数字字符串做乘法,得到一个结果数字串.

这次最后来了道大数乘法。。。做的时间比较晚。。。调试了一个小时。。。。。。。。。。思路就是模拟手算。好久没有做字符串了,感觉还是很多细节要注意啊。。。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值