LintCode 解题记录 Array 17.6.5

来源:互联网 发布:中国投资咨询公司 知乎 编辑:程序博客网 时间:2024/06/08 20:11

周六做的几道题目,今天周一抽一个上午总结一下。
首先贴两张图,用来激励自己吧。
这里写图片描述
这里写图片描述

LintCode Combinations
给定两个数n和k,返回1~n中的任取k个数的所有组合。
dfs+回溯。难度一般。

    vector<vector<int> > combine(int n, int k) {        // write your code here        vector<vector<int>> ret;        vector<int> tmp;        int cnt = 0;        if (n <= 0) return ret;        for (int i = 1; i <= n; i++) {            dfs(ret, tmp, cnt, i, n, k);        }        return ret;    }    void dfs(vector<vector<int>> &ret, vector<int> tmp, int cnt, int idx, int n, int k) {        cnt++;        tmp.push_back(idx);        if (cnt == k) {            ret.push_back(tmp);            return;        }        for (int i = idx+1; i <= n; i++) {            dfs(ret, tmp, cnt, i, n, k);        }    }

LintCode Continuous Subarray Sum
返回最大子序列和的beginIndex和endIndex。
思路和最大子序列和一样,用两个指针记录最大和的开始和目前的位置。

    vector<int> continuousSubarraySum(vector<int>& A) {        // Write your code here        vector<int> ret(2, 0);        vector<int> tmp;        int sum = 0, ans = INT_MIN;        for (int i = 0; i < A.size(); i++) {            sum += A[i];            tmp.push_back(i);            if (sum > ans) {                ans = sum;                ret[0] = tmp[0];                ret[1] = tmp[tmp.size()-1];            }            if (sum < 0) {                sum = 0;                tmp.clear();            }        }        return ret;    }

LintCode Find Peak Element
Challenge:时间复杂度O(logn)
一看到O(logn)多半是和二分有关了。这道题可以用画图来很直观的理解。题目给的条件很有用。
贴代码:

    int findPeak(vector<int> A) {        // write your code here        int left = 1, right = A.size()-2;        int mid = 0;        while (left < right) {            mid = (left+right) >> 1;            if (A[mid] < A[mid+1]) left = mid+1;            else if (A[mid] < A[mid-1]) right = mid-1;            else return mid;        }        return left;    }

LintCode Find the Duplicate Number
给定一个大小为n+1的数组,其中所有的数都在1~n之间,已知有且有一个数重复,问这个重复的数是多少。要求:1.不能改变原数组(不能用排序) 2.空间复杂度为O(1)(不能用Hash) 3.时间复杂度小于O(n^2)(不能用Brute-force)
第一种方法:1.O(nlogn) 二分搜索法
由于所有的数都是在1~n之间,那么对于数n/2,如果该数组中小于等于该数的次数大于n/2,则说明重复的数在1~n/2之间,否则就在n/2+1~n之间。所以时间复杂度是O(nlogn)。
代码:

    int findDuplicate(vector<int>& nums) {        // Write your code here        int min = 1, max = nums.size()-1;        int cnt = 0;        while (min < max) {            int mid = (min+max) >> 1;            cnt = 0;            for (int i = 0; i < nums.size(); i++) {                if (nums[i] <= mid) cnt++;            }            if (cnt <= mid) min = mid+1;            else max = mid;        }        return min;    }

第二种方法:O(n) Robert Floyd 算法
该算法常用于判断给定链表是否有环、以及求环的起点、以及求环的长度。贴一个写的不错的博客:
Robert Floyd Algorithm
其实这个算法自己画图稍微写几个公式就能理解了,关于此算法的应用有 Linked List Cycle + Linked List CycleII(直接在LintCode里搜索就能找到这两题)
那么本题用了这样的一个映射:index -> val。由于有重复的元素那么一定存在index1 != index2 但是 val1 == val2。那么x_n = f(x_n-1)按照这样的关系顺下去,最终环的起点就是要找的重复值。
代码:

    int findDuplicate(vector<int>& nums) {        // Write your code here        int slow, fast, t;        slow = fast = t = 0;        while (true) {            slow = nums[slow];            fast = nums[nums[fast]];            if (slow == fast) break;        }        while (true) {            slow = nums[slow];            t = nums[t];            if (slow == t) break;        }        return slow;    }

总结:
1.温故而知新,尝回来看看,看看做过的题,在思考提升一下。
2.掌握 Robert Floyd判断环的方法,重要,面试常考。