1-5

  • 两数之和

    给一个数组,和一个target,求数组里两个数字的和为target

       

    一遍哈希表

    遍历一遍把值和key放入哈希表中O(n)

    查找 target - nums[i] 是否在哈希表中O(1)

       

    vector<int> twoSum(vector<int>& nums, int target) {

        unordered_map<int, int> m;

        for (int i = 0; i < nums.size(); ++i) {

            if (m.count(target - nums[i])) {

                return (i, m[target - nums[i]]);

            }

            m[nums[i]] = i;

        }

        return {};

    }

    unorder_map <unorder_map>

    无序查找更快

       

  • 两数相加

    给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。

       

    很简单的题目

    节点忘记new 就直接用构造函数orz

    5+5最后一个进位忘记保存

       

  • 无重复字符的最长子串

    给定一个字符串,找出不含有重复字符的最长子串长度

    输入: "pwwkew"
    输出: 3
    解释: 无重复字符的最长子串是
     "wke",其长度为 3
     
    请注意,答案必须是一个子串
    "pwke" 是一个子序列 而不是子串。

   

unordered_map<char, int> m;

    for (int i = 0; i < len; i++) {

        m[s[i]] = i;

        cnt = 1;

        temp.push_back(s[i]);

        for (int j = i + 1; j < len; j++) {

            if (m.count(s[j])) break;

            else {

                m[s[j]] = j;

                cnt++;

                temp.push_back(s[j]);

            }

        }

        if (cnt > max) {

            ans = temp;

            max = cnt;

        }

        temp.clear();

        m.clear();

    }

   

   

s[i]开头的子串寻找,遍历过的进入m,直到找到有重复元素的为止

每换一次开头,清空一次m

大概O(n^2

(好像用一个普通bool 数组也可以代替map)

   

  • 两个排序数组的中位数

    给定两个大小为 m n 的有序数组 nums1  nums2 

    请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n))

    你可以假设 nums1  nums2 不同时为空。

       

    方法一:

    算法复杂度O(m+n)的方法,很显然是合并两个数组

    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {

      vector<int> num3;

        vector<int>::iterator it1, it2;

        it1 = nums1.begin();

        it2 = nums2.begin();

        while (it1 != nums1.end() || it2 != nums2.end()) {

            if (it1 != nums1.end() && it2 != nums2.end()) {

                if (*it1 < *it2) {

                    num3.push_back(*it1);

                    it1++;

                }

                else {

                    num3.push_back(*it2);

                    it2++;

                }

            }

            else if (it1 != nums1.end() && it2 == nums2.end()) {

                num3.push_back(*it1);

                it1++;

            }

            else if (it1 == nums1.end() && it2 != nums2.end()) {

                num3.push_back(*it2);

                it2++;

            }

        }

        double ans;

        int len = num3.size();

        if (len % 2 == 0) {

            ans = (num3[len / 2]* 1.0 +1.0*num3[len / 2 - 1]) / 2;

        }

        else

            ans = num3[int(len / 2)];

    return ans;

    }

    测试样例也太弱了

       

    方法二

    题目要求O(log(m+n))分治

       

    中位数的划分作用是,将一个数组划成两个长度相等子集,一个子集元素总是大于另一个子集元素。

       

    将AB 划分为连长度相同的两个部分,且其中一部分元素总是大于另一部分元素那么

    就可以求得中位数

       

    要确保这两个条件,只需要

    1的意思是前半部分数量 等于后半部分数量

    确保n大于等于m

       

    先不考虑临界值

    我们需要在[0,m]上搜索I 使

    前半部分最大数可能是A[i - 1] 或 B[j-1] 后半部分最小数可能是A[i]或B[j]

       

    [imin, imax]中搜索

       

    增大i还是减小i的决定条件是

    (1)

    找到目标停止搜索

       

    (2)

    意味着A[i]太小了

    i++

    (3)

    意味着i太大了

    i--

       

       

    处理边界条件

       

    class Solution {

    public double findMedianSortedArrays(int[] A, int[] B) {

    int m = A.length;

    int n = B.length;

    if (m > n) { // to ensure m<=n

    int[] temp = A; A = B; B = temp;

    int tmp = m; m = n; n = tmp;

    }

    int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;

    while (iMin <= iMax) {

    int i = (iMin + iMax) / 2;

    int j = halfLen - i;

    if (i < iMax && B[j-1] > A[i]){

    iMin = i + 1; // i is too small

    }

    else if (i > iMin && A[i-1] > B[j]) {

    iMax = i - 1; // i is too big

    }

    else { // i is perfect

    int maxLeft = 0;

    if (i == 0) { maxLeft = B[j-1]; }

    else if (j == 0) { maxLeft = A[i-1]; }

    else { maxLeft = Math.max(A[i-1], B[j-1]); }

    if ( (m + n) % 2 == 1 ) { return maxLeft; }

    int minRight = 0;

    if (i == m) { minRight = B[j]; }

    else if (j == n) { minRight = A[i]; }

    else { minRight = Math.min(B[j], A[i]); }

    return (maxLeft + minRight) / 2.0;

    }

    }

    return 0.0;

    }

    }

       

       

  • 最长回文子串

       

  • 把串逆序寻找最长公共子串

       

    X[i] == Y[j]dp[i][j] = dp[i-1][j-1] + 1

    X[i] != Y[j]dp[i][j] = 0

       

    巨大的坑

       

    需要检查字串索引与反向字串的原索引是否相同

    (不懂找)

       

  • 动态规划

    性质:回文串去掉头尾还是回文串

    dp[j][i]表示 j i 是否是回文串

       

    const int n = s.size();

        if (n == 0) return "";

        bool dp[n][n];

        memset(dp, 0, sizeof(dp));

        int maxlen = 1; //保存最长回文子串长度

        int start = 0; //保存最长回文子串起点

        for (int i = 0; i < n; ++i)

        {

            for (int j = 0; j <= i; ++j)

            {

                if (i - j < 2)

                {

                    dp[j][i] = (s[i] == s[j]);

                }

                else

                {

                    dp[j][i] = (s[i] == s[j] && dp[j + 1][i - 1]);

                }

                if (dp[j][i] && maxlen < i - j + 1)

                {

                    maxlen = i - j + 1;

                    start = j;

                }

            }

        }

        return s.substr(start, maxlen);

       

  • 中心扩展法

    把一个字母作为中心,向两边扩展

    分奇数偶数

       

    以上方法都是O(n^2

       

    还有一个复杂度为 O(n)O(n) 的 Manacher 算法

       

  • Manacher 算法
posted @ 2018-11-07 18:12  苦瓜与我常在  阅读(322)  评论(0)    收藏  举报