leetcode 题解 (1-500题,持续更新,part 1)

除了前面25道题目,为了省时间,后面只做hard的题目

part1包含了1000题以内的题目(未加锁部分hard题)

500-1000见LeetCode题解part2

1000题以上的见LeetCode题解part3

1. Two  Sum (Easy)

题意:给一个数组和一个数,求数组中哪两个数的和为这个数
题解:先排序,然后两个指针扫。容易证明这是可以的。因为如果当前的某个指针和已经扫过的某个数的和为目标值,那么则不可能达到现在这个状态。
时间复杂度是O(nlogn),不过如果数字都比较小,可以用计数的方法查找另一个数是否存在(或者用hash),这个解法为O(n)的解法。
语言:C++
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdlib.h>
#include <assert.h>

using namespace std;


class Solution {
struct Node{
    int value;
    int index;
    const bool operator < (const Node & b) {
        return value < b.value;
    }
};

public:
    vector<int> twoSum(vector<int> &nums, int target) {
        int len = nums.size();
        Node *node = new Node[nums.size()];
        for(size_t i = 0;i < nums.size(); ++i){
            node[i].value = nums[i];
            node[i].index = i;
        }

        sort(node, node + len);
        size_t left = 0, right = len - 1;
        int idL = - 1, idR = -1;
        while(left < right){
            if(node[left].value + node[right].value == target){
                idL = node[left].index;
                idR = node[right].index;
                break;
            }else if(node[left].value + node[right].value < target){
                ++left;
            }else{
                --right;
            }
        }
        delete node;
        assert(idL != -1);
        vector<int> ans(2);
        ans[0] = idL;
        ans[1] = idR;
        return ans;

    }
};

int main()
{
    vector<int> num(3);
    int target = 6;
    num[0] = 3; num[1] = 2; num[2] = 4;
    Solution s;
    vector<int> ans = s.twoSum(num, target);

    cout<<ans[0]<<" "<<ans[1]<<endl;
    return 0;
}

2. Add Two Numbers (Medium)

题意:给两个链表,每个链表表示一个数字(逆序的,个位在最前面),求他们的和,返回同样的格式(一个链表)
题解:简单的模拟加法过程即可
语言:C++

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode rootNode(0);
        ListNode *pCurNode = &rootNode;
        int a = 0;
        while (l1 || l2)
        {
            int v1 = (l1 ? l1->val : 0);
            int v2 = (l2 ? l2->val : 0);
            int temp = v1 + v2 + a;
            a = temp / 10;
            ListNode *pNode = new ListNode((temp % 10));
            pCurNode->next = pNode;
            pCurNode = pNode;
            if (l1) l1 = l1->next;
            if (l2) l2 = l2->next;
        }
        if (a > 0)
        {
            ListNode *pNode = new ListNode(a);
            pCurNode->next = pNode;
        }
        return rootNode.next;

    }
};

把上面的模换成下面的
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode rootNode(0);
        ListNode *pCurNode = &rootNode;
        int a = 0;
        while (l1 || l2)
        {
            int v1 = (l1 ? l1->val : 0);
            int v2 = (l2 ? l2->val : 0);
            int temp = v1 + v2 + a;
            a = temp > 9;
            ListNode *pNode = new ListNode(temp - a * 10);
            pCurNode->next = pNode;
            pCurNode = pNode;
            if (l1) l1 = l1->next;
            if (l2) l2 = l2->next;
        }
        if (a > 0)
        {
            ListNode *pNode = new ListNode(a);
            pCurNode->next = pNode;
        }
        return rootNode.next;

    }
};

3. Longest Substring Without Repeating Characters(Medium)

 题意:给定一个字符串,找出没有重复字符的最长子串。
题解:首先可以线性时间求解出当前字符上一次出现的位置,用一个数组last_pos保存下来。然后可以得到,一个子串(从begin开始到end位置结束的串),没有重复字符当且仅当在这个子串中last_pos() < b。
解法就是枚举子串开始位置i,然后用index索引枚举结束位置。注意到如果j > i,那么从j开始的最长不重复子串的末尾一定在以i开始的那个最长子串末尾的后面(至少相等)。也就是说index不用从i 枚举,而是从上一次枚举的位置开始,这样就保证了线性的时间,每次index都会加1。
渐进时间复杂度:O(n)
语言: python
class Solution(object):
    def lengthOfLongestSubstring(self, s):
        lens = len(s);
        w = [-1] * 100;
        last_pos = [0] * lens;
        #pos位置的字符上一次出现的位置,第一次出现,标记为-1
        for pos, c in enumerate(s):
            last_pos[pos] = w[ord(c) - ord('a')];
            w[ord(c) - ord('a')] = pos;
        ans = 0;
        index = 0;

        for i in range(lens):
            while(index < lens - 1 and last_pos[index + 1] < i):
                index = index + 1;
            ans = max(ans,index - i + 1);

        return ans;

4. Median of Two Sorted  Arrays (Hard)

题意:两个有序数组,求中值
题解:可以使用中间二分形式进行,每次判断中间的值的大小,舍弃不可能是答案的某个数组的一半,当数组一个已经为空时,直接得到答案。具体如下:
      对于两个数组: a[apre, amid,asuf],b[apre,bmid,bsuf],pre表前半段,suf表后半段,mid表中间元素(pre和suf可为空)。则答案在这6个段中的一个。(假设pre和suf都非空,因为如果为空,答案显然)比较a[amid]和b[bmid],如果a[amid] < b[bmid],那么可以确定顺序的有a[apre] <= a[amid] <= b[bmid] <= b[bsuf]。故而可以根据实际情况舍弃掉a[apre]或者b[bsuf]。那什么情况舍弃哪一个呢?有比较多的情况需要考虑。这个 方法虽然可以,但是到最后又非常多的边界需要判断,非常容易混乱。而如果不是取中位,而是k/2位的话,边界简单得多,思路和上面一样,只不过舍弃的情况没那么复杂。
时间复杂度(O(logn)

#include <iostream>
#include <vector>

using namespace std;


double findKth(int *a, int m, int *b, int n, int k)
{
    if (m > n)
        return findKth(b, n, a, m, k);

    if (m == 0)
        return b[k - 1];

    if (k == 1)
        return a[0] < b[0] ? a[0] : b[0] ;
    int pa = k / 2 < m ? k / 2 : m, pb = k - pa;
    if (a[pa - 1] < b[pb - 1])
        return findKth(a + pa, m - pa, b, n, k - pa);
    else if (a[pa - 1] > b[pb - 1])
        return findKth(a, m, b + pb, n - pb, k - pb);
    else
        return a[pa - 1];
}
double findMedianSortedArrays(int* A, int m, int* B, int n) {

        int total = m + n;
        if (total & 0x1)
            return findKth(A, m, B, n, total / 2 + 1);
        else
            return (findKth(A, m, B, n, total / 2)
                    + findKth(A, m, B, n, total / 2 + 1)) / 2;
}


int main()
{
    int *a ,b[] = {1};
    cout<<findMedianSortedArrays(a,0,b,1)<<endl;

}

 5. Longest Palindromic Substring (Medium)

题意:最大回文子串
题解:manacher算法;枚举中心,利用前面的信息。具体见manacher算法,无需多说。
渐进时间复杂度(O(n))

#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
    string longestPalindrome(string s) {
        string str(s.size() * 2 + 3,'#');
        str[0] = '$';
        str[s.size() * 2 + 2] = '@';
        for(size_t i = 0;i < s.size(); ++i){
            str[i * 2 + 2] = s[i];
        }
        return findLongestPalindrome(str, s);
    }

    string findLongestPalindrome(string str, string s){
        size_t *d = new size_t[str.size()];
        size_t mx = 0, mxId = 0, longestLenth = 1 , longestLenthPos = 0;
        d[0] = 1;

        for(size_t i = 1;i < str.size(); ++i){

            if(mx <= i)  d[i] = 1;
            else d[i] = min(d[2 * mxId - i] , mx - i);

            while(str[i - d[i]] == str[i + d[i]]) ++d[i];

            if(d[i] + i > mx){
                mx = d[i] + i;
                mxId = i;
            }
            if(d[i] > longestLenth){
                longestLenth = d[i] - 1;
                longestLenthPos = i;
            }
        }
        delete d;
        size_t startPos = (longestLenthPos - longestLenth) / 2;
        return s.substr(startPos, longestLenth);
    }
};

int main()
{
    Solution s;
    string str = "ccd";
    cout<<s.longestPalindrome(str)<<endl;

}

6. ZigZag Conversion

题意:将一个字符串转化成zigZag形状,然后按行重新排列输出。
题解:简单模拟。
不过编译器好像跟本地的不太一样,对关于vector初始化,需要push_back过才能取出,否则是runtimeError 而不是取出空串。
代码:
#include <iostream>
#include <string>
#include <vector>
using namespace std;

string convert(string s, int nRows) {

    if(nRows <= 1 || s.length() <= nRows)
        return s;
    vector<string> zigZags(nRows);

    int curRow = 0, step = 1;
    for (string::iterator s_iter = s.begin(); s_iter != s.end(); ++s_iter){
        zigZags[curRow].push_back(*s_iter);

        if(curRow == 0) step = 1;
        else if(curRow == nRows - 1) step = -1;
        curRow += step;
    }
    s.clear();
    string::iterator s_it;
    for(vector<string>::iterator vit = zigZags.begin(); vit != zigZags.end(); ++vit){
        s += *vit;
    }
    return s;
}

int main()
{
    string s =  "PAYPALISHIRING;
    int nRows = 3;
    cout<<convert(s, nRows)<<endl;
    return 0;
}

7. Reverse Integer

题意:将数字翻转
题解:直接转,注意前导零和溢出即可
代码:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

int reverse(int x) {
    if (x == 0) return 0;
    int sign = (x > 0) * 2 - 1;
    long long y = abs(x);
    long long res = 0;
    while(y > 0){
        res = res * 10 + y % 10;
        y /= 10;
    }
    res = sign * res;
    if(res > (1LL << 31) - 1 || res < -(1LL << 31))
        res = 0;
    return res;
}


int main()
{
    cout<<reverse(-123)<<endl;
    return 0;
}


8. String to Integer (atoi)

题意:按照题目将字符串转成int。规则是,前缀不合法输出前缀,合法前缀为空输出0,超出int输出maxint,小于minint输出minint即可
题解:主要是题目各种输入情况没有说明

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

int myAtoi(string str) {
    int sign = 1;
    int max_int = 2147483647;
    int min_int = -2147483648;
    string::iterator s_it = str.begin();
    while(s_it != str.end() && *s_it == ' ') ++s_it;
    if(s_it != str.end()  && (*s_it == '+' || *s_it == '-')){
        sign = ((*s_it == '+') * 2 - 1);
        ++s_it;
    }
    long long res = 0;
    int num = 0;
    for(; s_it != str.end() ; ++ s_it){
        if(*s_it < '0' || *s_it > '9') break;
        res = res * 10 + sign * (*s_it - '0');
        ++num;
        if(res > max_int) {
                res = max_int;
                break;
        }
        if(res < min_int){
            res = min_int;
            break;
        }
    }
    if(num == 0) return 0;
    return res;
}

int main()
{
    cout<<myAtoi("1")<<endl;
    return 0;
}

9. Palindrome Number

题意:判断一个整数是不是回文数
题解:将x的后半段倒置,然后和前半段比较即可,注意可能有奇数个数字或偶数,末尾有0,以及负数的情形即可。
class Solution {
public:

    bool isPalindrome(int x) {
        if(x < 0 || (x != 0 && x % 10==0)) 
            return false;

        int y = 0;
        while(x > y){
            y = y * 10 + x % 10;
            x /= 10;
        }
        return (x == y) || (x == y / 10);
    }
};

10. Regular Expression Matching

题意:简单的正则表达式,判断给定字符串是不是符合给定的模式(只包含字符和*以及.)
题解:按照多年的acm经验,一眼看出是简单DP题。
dp[i][j]表示字符串和0到i个位置的子串,是否能与模式串0到j匹配。然后就分几种情况进行转移即可。注意在前面增加了空串(即0为置表示空串),能够简化代码。
解如下:
设d[i][j]表示原字符串的0到i能否和模式串的0到j匹配。字符串从1位置开始,0表示空串(方便处理)
故d[0][0] = 1,下面求转移方程
分三种情况:
p[j] = '.', p[j] = '*’和其他
当p[j] = '*' 时,要使得d[i][j] = 1,必须有如下情况之一发生
    a.d[i][j - 2] = 1 (p[j - 1], p[j] 匹配空串)
    b.d[i - 1][j - 1] = 1且(s[i] = p[j - 1]或 p[j - 1] = '.')
当p[j] = '.', 要使得d[i][j] = 1,必须有
    d[i - 1][j - 1] = 1
其他:
    d[i - 1][j - 1] = 1且 s[i] = p[j]


class Solution {
public:
    static const size_t maxN = 1000;
    static bool dp[maxN][maxN];
    bool isMatch(string s, string p) {
        size_t slen = s.length();
        size_t plen = p.length();

        dp[0][0] = true;
        for (size_t i = 0; i <= slen; ++i)
            for (size_t j = 1; j <= plen; ++j)
                if (p[j - 1] == '*')
                     dp[i][j] = dp[i][j - 2] ||  (i > 0 && (s[i - 1] == p[j - 2] || p[j - 2] == '.') && dp[i - 1][j]);
                else dp[i][j] = i > 0 && dp[i - 1][j - 1] && (s[i - 1] == p[j - 1] || p[j - 1] == '.');

        return dp[slen][plen];
    }
};
bool Solution::dp[maxN][maxN];

11. Container With Most Water

题意:给定一组数据,d0,d1,...dn,表示第i个位置有长为di的竖线,问这些竖线中那两根和x轴围成的容器能装最多的水?
题解:考虑双指针。从两边开始,注意到,如果两个指针(i和j)的一边比较短,那么,这一个边就可以抛弃掉,因为它不可能是最优解(不妨设i比较短(或者等长),假设它和另外一根线k组成最优解,那么k可能在i前面,ij中间,或者j后面。首先k不可能在i前面或者j后面,不然的话,我们不可能把k抛弃掉。另外,它也不可能在ij中间,因为如果在ij中间的话ik肯定没有ij这一对好,所以i可以抛弃掉)。
class Solution {
public:
    int maxArea(vector<int>& height) {
        int ans = 0, left = 0, right = height.size() - 1;
        while (left < right) {
            ans = max(ans, min(height[left], height[right]) * (right - left));
            if (height[left] < height[right])
                ++left;
            else
                --right;
        }
        return ans;
    }

};

12. Integer to Roman

题意:将一个整数转换成罗马数字(罗马数字参考http://baike.baidu.com/link?url=uhmgSPP-MZpOKblUj9gO6pvpuLzgx2XteJGqyPoJjmrTpRZ8H_Jx_WUz2gmIxMwnLKKZKpnkPOUVbkMc4RY0fjYjnYU4Y6snyWn0lmLXu9gHxsUoLi7PgJBr_cdm-NNd)
数字在1到3999之间
简单题,这是别人写的代码
class Solution {
public:
    string intToRoman(int num) {
        string M[] = {"", "M", "MM", "MMM"};
        string C[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
        string X[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
        string I[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
        return M[num / 1000] + C[(num % 1000) / 100] + X[(num % 100) / 10] + I[num % 10];        
    }
};

13. Roman to Integer

题意:将罗马数字转换成整数
题解:简单题
别人的代码:http://blog.csdn.net/booirror/article/details/43197595
class Solution {
public:

    int getVal(char a){
        switch (a) {
        case 'I':
            return 1;
        case 'V':
            return 5;
        case 'X':
            return 10;
        case 'L':
            return 50;
        case 'C':
            return 100;
        case 'D':
            return 500;
        case 'M':
            return 1000;
        }
        return 0;
    }

    int romanToInt(string s){
        int res = 0;
        char max = 'I';
        for (int i = s.size()-1; i >= 0; --i) {
            if (getVal(s[i]) >= getVal(max)) {
                max = s[i];
                res += getVal(s[i]);
            } else {
                res -= getVal(s[i]);
            }
        }
        return res;
    }


};

14. Longest Common Prefix

题意:给定一个字符串数组,找出他们的最长公共前缀。
题解:简单题
class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        string prefix = "";
        if(strs.size() < 1) return prefix;
        for(size_t i = 0; i < strs[0].size();prefix += strs[0][i++])
            for(size_t j = 0;j < strs.size(); ++j)
                if(i >= strs[j].size() || strs[j][i] != strs[0][i]) return prefix;
        return prefix;
    }
};

15. 3Sum

题意:给定一个数组,三个数和为0的数对有哪些
题解:为了避免重复,先排序。先枚举第一个数,然后2和3 用two sum的方法。下面代码修改自
1.two sum(不过这里不需要给出下标),渐进时间复杂度为)(n^2)。容易改成计数或者hash的做法,这里不给出。

quadruple

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        int len = nums.size();

    for(size_t i = j + 1; i < len; ++i){
            int target = -nums[i] - nums[j];
            size_t left = i + 1, right = len - 1;
            while(true){
                while(left > i + 1 && left < right && nums[left] == nums[left - 1]) ++left;
                while(right < len - 1 && left < right && nums[right] == nums[right + 1]) --right;
                if(left >= right) break;
                if(nums[left] + nums[right] == target){
                    vector<int> triplet(3, 0);
                    triplet[0] = nums[i];
                    triplet[1] = nums[left++];
                    triplet[2] = nums[right--];
                    ans.push_back(triplet);
                }else if(nums[left] + nums[right] < target){
                    ++left;
                }else{
                    --right;
                }
            }
        }

        return ans;

    }
};

16. 3Sum Closest

题意:给定一个数组和一个目标值,求离目标最近的三个数的和是多少?
题解:和15没啥不一样,改一下代码即可
class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {        
        sort(nums.begin(), nums.end());
        int len = nums.size();
        int ans = nums[0] + nums[1] + nums[2];
        int dis = abs(ans - target);
        for(size_t i = 0; i < len; ++i){
            if(i > 0 && nums[i] == nums[i - 1]) continue;
            size_t left = i + 1, right = len - 1;
            int T = target - nums[i];
            while(true){
                while(left > i + 1 && left < right && nums[left] == nums[left - 1]) ++left;
                while(right < len - 1 && left < right && nums[right] == nums[right + 1]) --right;
                if(left >= right) break;
                if(abs(nums[left] + nums[right] - T) < dis){
                    dis = abs(nums[left] + nums[right] - T);
                    ans =  nums[left] + nums[right] + nums[i];
                }
                if(dis == 0) break;
                if(nums[left] + nums[right] < T){
                    ++left;
                }else{
                    --right;
                }
            }
        }
        return ans;

    }
};

17. Letter Combinations of a Phone Number

题意:给定一串数字字符串,问按照电话上的字母转换规则,能转换成那些字母的字符串。
题解:可以有多种方法解决,我是利用计数迭代的方法,遍历所有的排列。

class Solution {
public:
    vector<string> letterCombinations(string digits) {
        string kvmaps[8] = {"abc", "def", "ghi",  "jkl",  "mno",  "pqrs",  "tuv",  "wxyz" };
        int  length[8] = {3,3,3,3,3,4,3,4};
        vector<string> ans;
        if(digits == "") return ans;
        vector<int> iter(digits.size(),0);
        bool flag = true;
        int digit;
        while(flag){
            string s = "";
            for(int i = 0 ; i < digits.size(); ++i){
                digit = digits[i] - '0';
                if(digit == 0) digit = 10;
                s += kvmaps[digit - 2][iter[i]];
            }
            ans.push_back(s);
            ++iter[0];
            for(int i = 0; i < digits.size(); ++i){
                digit = digits[i] - '0';
                if(digit == 0) digit = 10;
                if(iter[i] >= length[digit - 2]){
                    if(i == digits.size() - 1){flag = false; break;}
                    else{
                        iter[i] = 0;
                        ++iter[i + 1];
                    }

                }

            }

        }
        return ans;

    }
};

18. 4Sum

题意:给定一个数组和一个目标整数,求数组中不重复的四元组的和为目标的四元组
题解:在15题加一层循环即可

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums,int T) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        int len = nums.size();
        for(size_t j = 0;j < len; ++j){
            if(j > 0 && nums[j] == nums[j - 1]) continue;    
            for(size_t i = j + 1; i < len; ++i){
                    if(i > j + 1 && nums[i] == nums[i - 1]) continue;
                    int target = T - nums[i] - nums[j];
                    size_t left = i + 1, right = len - 1;
                    while(true){
                        while(left > i + 1 && left < right && nums[left] == nums[left - 1]) ++left;
                        while(right < len - 1 && left < right && nums[right] == nums[right + 1]) --right;

                        if(left >= right) break;
                        if(nums[left] + nums[right] == target){
                            vector<int> quadruples(4, 0);
                            quadruples[0] = nums[j];
                            quadruples[1] = nums[i];
                            quadruples[2] = nums[left++];
                            quadruples[3] = nums[right--];
                            ans.push_back(quadruples);
                        }else if(nums[left] + nums[right] < target){
                            ++left;
                        }else{
                            --right;
                        }
                    }
                }
        }
        return ans;

    }
};

19. Remove Nth Node From End of List

题意:通过一次遍历,将链表的倒数第n个删掉
题解:虽然说是一次遍历,实际上只不过是两次遍历写在一个循环里面罢了。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* h1 = head, *h2 = head;
        while(n-->0) h2 = h2->next;
        if(!h2) return head->next;
        h2 = h2->next;
        while(h2 != NULL){
            h1 = h1->next;
            h2 = h2->next;
        }
        h1->next = h1->next->next;   // the one after the h1 need to be removed
        return head;
}
};

20. Valid Parentheses

题意: 给定一个包含三种括号的字符串,判断是否是合法的括号嵌套。
题解:模拟匹配过程即可
class Solution {
public:
    bool isValid(string s) {
        stack<char>S;
        if(s.empty()) return true;
        if(s[0] != '(' && s[0] != '[' && s[0] != '{') return false;
        S.push(s[0]);
        for(int i = 1;i < s.length(); ++i){
            if(s[i] == ')' || s[i] == ']' || s[i] == '}'){
                if(S.empty()) return false;
                if(s[i] == ')' && S.top() != '(' || s[i] == ']' && S.top() != '[' || s[i] == '}' && S.top() != '{') return false;
                S.pop();
            }else{
                S.push(s[i]);
            }
        }
        return S.empty();
    }
};

21. Merge Two Sorted Lists

题意:将两个有序链表合并(从小到大)
题解:简单题
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1 == NULL) return l2;
        if(l2 == NULL) return l1;
        ListNode * listHead, *p;
        listHead = p = new ListNode(0);
        while(l1 && l2){
            if(l1->val < l2->val) {
                p->next = l1;
                l1 = l1->next;
            }else{
                p->next = l2;
                l2 = l2->next;
            }
            p = p->next;
        }
        if(l1 != NULL) p->next = l1;
        else p->next = l2;
        p = listHead->next;
        delete listHead;
        return p;
    }
};

22. Generate Parentheses

题意:给定一个n,生成所有可能长度为n的嵌套括号组合
题解:可以用dfs求解。不过我这里用bfs,然后用位标记法代替字符串以节省内存。

class Solution {
public:
    vector<string> generateParenthesis(int n) {
        vector<string> ans;
        n *= 2;
        //1是右括号,0为左括号
        cout<<'yes';
        queue<pair<long long,char> > Q;
        Q.push(make_pair(0LL,0x01));
        while(!Q.empty()){
            pair<long long,char> p = Q.front();
            Q.pop();
            if(p.second == n){
                ans.push_back(genString(p.first,n));
                continue;
            } 
            //添加左括号
            char leftParenthesisNum = p.second - bitCount(p.first);
            //cout<<leftParenthesisNum<<" p"<<endl;
            if(leftParenthesisNum < n / 2) Q.push(make_pair(p.first,p.second + 1));
            if(leftParenthesisNum > p.second - leftParenthesisNum)Q.push(make_pair(p.first | (1 << p.second), p.second + 1));1<<endl;
        }
        return ans;
    }
    //计算位数
    char bitCount(unsigned long long n) 
    { 
        n = (n &0x5555555555555555) + ((n >>1) &0x5555555555555555) ; 
        n = (n &0x3333333333333333) + ((n >>2) &0x3333333333333333) ; 
        n = (n &0x0f0f0f0f0f0f0f0f) + ((n >>4) &0x0f0f0f0f0f0f0f0f) ; 
        n = (n &0x00ff00ff00ff00ff) + ((n >>8) &0x00ff00ff00ff00ff) ; 
        n = (n &0x0000ffff0000ffff) + ((n >>16) &0x0000ffff0000ffff) ; 
        n = (n &0x00000000ffffffff) + ((n >>32) &0x00000000ffffffff) ; 
        return char(n&0xff) ; 
    }
    
    string genString(long long parentheses, int n){
        string s = "";
        for(int i = 0;i < n; ++i){
            if((parentheses>>i) & 1) s+=')';
            else s+= '(';
        } 
        return s; 
    }
};

23. Merge k Sorted Lists

题意:将k个有序链表合并成一个
题解:用优先队列即可。主义c++优先队列是大顶堆
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    struct cmp
    {
        bool operator()(ListNode * &a,ListNode * &b){
            return a->val > b->val;
        }
    };
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        priority_queue<ListNode *,vector<ListNode *>, cmp>Q;
        ListNode *head,*p;
        head = p = new ListNode(0);
        for(size_t i = 0;i < lists.size(); ++i)
            if(lists[i] != NULL) Q.push(lists[i]);
        while(!Q.empty()){
            ListNode *node = Q.top();
            Q.pop();
            p->next = node;
            p = p->next;
            if(node->next) Q.push(node->next);
        }
        p = head->next;
        delete head;
        return p;
    }
};

24. Swap Nodes in Pairs

题意:交换链表中的连续的对(交换(1,2),(3,4 ) 以此类推)。
题解:模拟即可
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        int index = 0;
        ListNode* l1, *l2, *tmp = new ListNode(0);
        tmp->next = head;
        head = tmp;
        while(tmp){
            if(!tmp->next) break;
            l1 = tmp->next;
            if(!l1->next) break;
            l2 = l1->next;
            tmp->next = l2;
            l1->next = l2->next;
            l2->next = l1;
            tmp = l1;
        }
        tmp = head->next;
        delete head;
        return tmp;
    }
};

31. Next Permutation

题意:给定一个数组,求排列中,下一个排列。
题解:注意可能有重复数字。模仿我们人计算过程。首先判断是否为最后一个排列,是就输出翻转后的结果。不然,将排列分成三部分(我们假设长度大于等于2,第一部分可为空)[a, b, c](a,c为序列,b为一个数字),其中c呈倒序,而且b小于c的第一个数字,那么下一个排列将为,a不变,将b和c最后一个大于它的数交换,然后将c翻转。(这个是很容易想到的,实现也简单)
class Solution {
public:
    
    int decreaseLen(vector<int> & nums){
        int len = 1;
        for(int i = nums.size() - 2; i >= 0 && nums[i] >= nums[i + 1] ;--i,++len);
        return len;
    }
    void nextPermutation(vector<int>& nums) {
        if(nums.size() <= 1) return;
        int len = decreaseLen(nums);
        if(len == nums.size()){reverse(nums.begin(),nums.end());return;}
        int id = nums.size() - len - 1;
        int pos = id;
        //找到后面最后一个大于它的数
        for(int i = id + 1;nums[id] < nums[i] && i <= nums.size(); ++i)++pos; 
        pos = min(pos,int(nums.size() - 1) );
        swap(nums[id],nums[pos]);
        reverse(nums.begin() + id + 1,nums.end());
    }
};

32. Longest Valid Parentheses

题意:给一个包含'('和')'的括号串,求最长的合法配对子括号串长度。
题解:动态规划,dp[i]表示以第i个位置作为结束时的最长串长度。
当s[i] == '('时,dp[i] = 0.
当s[i] == ')'时候,看前面那个配对到哪里,然后这个括号能否配对,如果不能,也是dp[i] = 0,能的话递推。
class Solution {
public:
    int longestValidParentheses(string s) {
        int n = s.length();
        if(n <= 1) return 0;
        vector<int> dp(n);
        int ans = 0;
        dp[0] = 0;
        for(int i = 1; i < n; ++i){
            if(s[i] == '(') dp[i] = 0;
            else{
                if(s[i - 1] == '('){
                    if(i == 1) dp[i] = 2;
                    else dp[i] = dp[i - 2] + 2; 
                }else{
                    int idx = i - 1 - dp[i - 1];
                    if(idx >= 0 && s[idx] == '('){
                        if(idx > 0)
                        	dp[i] = dp[i - 1] + dp[idx - 1] + 2;
                        else  dp[i] = dp[i - 1] + 2;
                    }else dp[i] = 0;
                }
            }
            ans = max(ans,dp[i]);
        }
    	return ans;
    }
};

在s前面补一个'('可以少个两个判断条件。
class Solution {
public:
    int longestValidParentheses(string s) {
        int n = s.length();
        if(n <= 1) return 0;
        s = ')' + s; ++n;
        vector<int> dp(n);
        int ans = 0;
        dp[0] =  dp[1] = 0;
        for(int i = 2; i < n; ++i){
            if(s[i] == '(') dp[i] = 0;
            else{
                if(s[i - 1] == '('){
                    if(i == 1) dp[i] = 2;
                    else dp[i] = dp[i - 2] + 2;
                    
                }else{
                    int idx = i - 1 - dp[i - 1];
                    if(s[idx] == '('){
                        dp[i] = dp[i - 1] + dp[idx - 1] + 2;
                    }else dp[i] = 0;
                }
            }
            ans = max(ans,dp[i]);
        }
    	return ans;
    }
};

37. Sudoku Solver

题意:求解一个数独
题解:深度搜索和剪枝
‘class Solution {
public:
    void solveSudoku(vector<vector<char>>& board) {
        vector<vector<bool> >rowVis(9,vector<bool>(9,false));
        vector<vector<bool> >colVis(9,vector<bool>(9,false));
        vector<vector<bool> >lat (9,vector<bool>(9,false));
        
        for(int i = 0;i < 9; ++i)
            for(int j = 0;j < 9; ++j){
                if(board[i][j] == '.') continue;
                int x = board[i][j] - '1';
                rowVis[i][x] = colVis[j][x] = lat[(i / 3) * 3 + j / 3][x] = true;
            }
        dfs(board,rowVis,colVis,lat,0,0);
    }
    
    bool dfs(vector<vector<char>>& board,vector<vector<bool> >& rowVis,vector<vector<bool> >& colVis,vector<vector<bool> >&lat,int x,int y){
   
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值