這周主要實現了LeetCode Algorithms中的Divide-And-Conquer的題目,這里選擇二道題來分析,分別是Maximum Subarray(easy)、Merge k Sorted Lists(Hard)。
題目描述:Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array [-2,1,-3,4,-1,2,1,-5,4], the contiguous subarray [4,-1,2,1] has the largest sum = 6.
分析:這個題最開始的做法是采用了分治法,參考《算法分析》4.1的最大子數組問題??紤]最大值會出現的三種情況,即將數組分為三個部分,最大子序列可能會是前半部分或后半部分或者是跨越了中點的序列中,比如
對于
對于
最終返回三種計算中的最大的序列和即可。這樣的做法的時間復雜度是
分治法的結果如下:
class Solution {public: int maxSubArray(vector<int>& nums) { return findMaxArray(nums,0,nums.size()-1); } int findMaxArray(vector<int>& nums,int low, int high){ if(high == low){ return nums[low]; } else{ int mid = (high+low)/2; return max(findMaxArray(nums,low,mid),findMaxArray(nums,mid+1,high),findMaxCrossArray(nums,low,mid,high)); } } int findMaxCrossArray(vector<int>& nums, int low, int mid, int high){ int leftsum = -100, rightsum = -100; int sum = 0; for(int i = mid; i >= low;i--) { sum += nums[i]; if(sum>leftsum) leftsum = sum; } sum = 0; for(int i = mid+1; i <=high ;i++) { sum += nums[i]; if(sum>rightsum) rightsum = sum; } return leftsum+rightsum; } int max(int m1,int m2,int m3){ if(m1>=m2 && m1>=m3) return m1; else if(m2>=m1 && m2>=m3) return m2; else return m3; }}; 但是,這樣的分治法,其實是很麻煩的,RunTime為13ms??梢灾苯油ㄟ^優化把算法的復雜度降到
對于數組,我們可以這樣考慮:
我們定義
代碼的過程可以寫作下面的形式:
class Solution {public: int maxSubArray(vector<int>& nums) { int sum_now = 0; int sum_max = nums[0]; for(int i = 0;i < nums.size();i++){ sum_now += nums[i]; if(nums[i]>= sum_now) sum_now = nums[i]; if(sum_now >= sum_max) sum_max = sum_now; } return sum_max; }}; 可以看出此時的算法的復雜度只有
題目描述: Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. Subscribe to see which companies asked this question.
分析:其實這個題的難度并不大,可以直接通過歸并排序完成。最主要的就是了解歸并排序的流程。 歸并排序是典型的分治模式的算法,它主要是通過把

題目要求的是對多條鏈表的合并,需要注意的是鏈表的長度都是不一致,所以需要在合并過程時判斷是否應該繼續用某一序列的下一位來判斷取值。
代碼如下所示:
class Solution {public: ListNode* mergeKLists(vector<ListNode*>& lists) { if(lists.empty()) return nullptr; return mergesort(lists,0,lists.size()-1); } ListNode* mergesort(vector<ListNode*>& lists, int p, int r){ if (p<r) return merge(mergesort(lists,p,(p+r)/2),mergesort(lists,(p+r)/2+1,r)); else return lists[p]; } ListNode* merge(ListNode* l1, ListNode* l2){ if(l1 == NULL) return l2; if(l2 == NULL) return l1; ListNode* result = new ListNode(0); ListNode* head = result; while(l1 != NULL && l2 != NULL){ if(l1->val < l2->val){ head->next = new ListNode(l1->val); l1 = l1->next; } else{ head->next = new ListNode(l2->val); l2 = l2->next; } head = head->next; } if(l1 == NULL) head->next = l2; else if(l2 == NULL) head->next = l1; return result->next; }}; 直接使用歸并排序,每次都選擇分割兩個序列,算法負責度可以寫作
總結:其實這周實現的算法都不是很難,但是可能我更多的時間都花在了怎么去優化它們了,最開始總是有先入為主的想法,分治一定會比較快,但其實不盡然(當然也有可能是我想的分治法比較麻煩==)??傊?,我覺得這周選擇的題目不僅剛好把課上學到的分治法的分析思想用上了,也讓我學著去思考優化的問題,感覺收獲頗多,接下來還是要好好刷題^^
新聞熱點
疑難解答