寫在前面:
LeetCode這個網站相比不必多說了吧,凡是IT圈子的人應該都知道這個網站,最近開始準備找工作,當然也免不了上去刷刷題,做一做比較經典的編程題,剛好看到LeetCode有個周練,便報名參加。 進入正題:
概要: 總共4個題,一個半小時的時間安排。題目分級為,兩個easy,一個medium,一個hard。 第一題 624. Maximum Distance in Arrays
題目描述:
Given m arrays, and each array is sorted in ascending order. Now you can pick up two integers from two different arrays (each array picks one) and calculate the distance. We define the distance between two integers a and b to be their absolute difference |a-b|. Your task is to find the maximum distance.
這道題一開始有點卡,題意就是找到非同一個數組中最大值,和非同一個數組中的最小值,使得兩數相減的值最大,給出來的數組都是已經排序完成了的,唯一的約束就是不能再同一個數組中選擇最大值和最小值;
這道題有點藉助了一道經典的題的思路,叫做求最長遞增子序列,使用動態規劃的方法來做,首先,選取第一個一維數組,取兩端構建最大值和最小值,然後從下一個一維數組開始遍曆,遍曆到每一個一維數組,我們假設其中某一個值要在該數組中選擇,所以有兩種方法,選擇該數組的 最大值 - 之前維護的最小值,或者 之前維護的最大值 - 該數組的最小值, 使用一個外部變數來維護一個差值最大的結果;同時,在遍曆下一個一維數組之前,將該一維數組的最大值和最小值拿去更新一直以來在維護的最大值和最小值;
代碼如下:
//TLE Solutionclass Solution {public: int maxDistance(vector<vector<int>>& arrays) { int lens = arrays.size(); int ret = 0; for(int i=0;i<lens;i++){ for(int j=0;j<lens;j++){ if(i != j){ ret = max(ret, arrays[i].back()-arrays[j].front()); } } } return ret; }};class Solution {public: int maxDistance(vector<vector<int>>& arrays) { //用一個外部變數來維護最大距離差值 int ret = 0; int min_val = arrays[0].front(), max_val = arrays[0].back(); for(int i=1;i<(int)arrays.size();i++){ //每一次計算分別選擇當前array的最大值,最小值來計算差值,並儲存最大值 ret = max(arrays[i].back()-min_val, ret); ret = max(max_val-arrays[i].front(), ret); //更新當前array之前的所有array維護出來的最大值和最小值 min_val = min(min_val, arrays[i].front()); max_val = max(max_val, arrays[i].back()); } return ret; }};
第二題 623. Add One Row to Tree
題目描述: Given the root of a binary tree, then value v and depth d, you need to add a row of nodes with value v at the given depth d. The root node is at depth 1.
The adding rule is: given a positive integer depth d, for each NOT null tree nodes N in depth d-1, create two tree nodes with value v as N's left subtree root and right subtree root. And N's original left subtree should be the left subtree of the new left subtree root, its original right subtree should be the right subtree of the new right subtree root. If depth d is 1 that means there is no depth d-1 at all, then create a tree node with value v as the new root of the whole original tree, and the original tree is the new root's left subtree.
很簡單的一個題,樹形結構,又是它,第一選擇就是遞迴來做,明白題目的意思以後分兩種情況;
一種是直接在根節點插入一行節點;另一種情況就是在樹種插入一行節點;選擇的方法就是dfs來做,插入完節點之後就撤;
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */class Solution {private: void dfs(TreeNode* root, int v, int d, int cur){ //判斷邊緣情況,符合的話記得返回,不符合繼續dfs if(root == NULL) return; if(cur == d){ TreeNode* new_left = new TreeNode(v); new_left->left = root->left; TreeNode* new_right = new TreeNode(v); new_right->right = root->right; root->left = new_left; root->right = new_right; return; } dfs(root->left, v, d, cur+1); dfs(root->right, v, d, cur+1); }public: //遞迴解決樹的深度優先問題 TreeNode* addOneRow(TreeNode* root, int v, int d) { int real = d - 1; //如果real為根節點,所以直接用來作為根節點,左節點為原來的樹 if(real == 0){ TreeNode* ret = new TreeNode(v); ret->left = root; return ret; } else{ TreeNode* ret = root; dfs(root, v, real, 1); return ret; } }};
第三題 625. Minimum Factorization
題目描述:
Given a positive integer a, find the smallest positive integer b whose multiplication of each digit equals to a.
If there is no answer or the answer is not fit in 32-bit signed integer, then return 0.
身為medium難度的一題,其實只要把其中的規則摸清楚,medium甚至於hard的題目反而坑會比較少;
這道題要求給定一個數a,返回一個數b,是的將數b的每一位相乘以後都能得到a;
由此可以判斷出,要想任何數相乘以後得到該數本身,那就和它自己的約數有關,在這一題,考慮的是單位元相乘,所以需要排除掉約數中有不可再約的非單位元,也就是說,可以將一個數a分解成質因數,並且這些質因數不能超過10;所以我們可以用一個資料結構來維護分解之後的質因數,然後由於要使得最終組合出來的b最小而且在unsigned int表示範圍內;所以質因數中,2和3可以組合成更大的數(不超過10),這樣使得b的範圍更加收斂;
在這裡組合質因數有一個規律,首先儘可能的用3個2組成一個8,剩下的2和3排成一列,如果總數為奇數,取第一位放在b的第一位,然後剩下的兩兩組合;如果直接總數為偶數,那就直接兩兩組合;這樣可以使得最終組成的b最小;
代碼如下:
class Solution {private: // 用一個map來維護 map<int, int> table; bool initNums(int a){ int tmp = a, divisor = 2; while(tmp != 1){ if(divisor >= 10) return false; if(tmp%divisor == 0){ table[divisor]++; tmp /= divisor; } else{ divisor++; } } return true; } // 三個2結合成8,剩下的2和3組成序列,如果為基數,第一個數保留 // 序列中剩下的數兩兩相乘來組成新的數放入map // 組合map裡面的數,如果是int範圍內的輸出,否則輸出0 int deal(map<int, int>& table){ int tmp = table[2] / 3, rest = table[2] % 3; table[8] += tmp; vector<int> nums(rest, 2), nums_tmp(table[3], 3); table.erase(2); table.erase(3); nums.insert(nums.end(), nums_tmp.begin(), nums_tmp.end()); int lens = nums.size(), i = 0; if(lens > 0){ if(lens&0x01){ i = 1; table[nums[0]] = 1; } for(;i<lens;i+=2){ int res = nums[i]*nums[i+1]; table[res]++; } } long long res = 0; for(auto k=table.begin();k!=table.end();k++){ for(int i=1;i<=k->second;i++){ res = res*10 + k->first; } } if(res>=INT_MIN&&res<=INT_MAX) return (int)res; else return 0; }public: // 先將數用質數表示 int smallestFactorization(int a) { if(a == 1) return 1; // 判斷能否用10以內的質數表示,不能的話返回false if(!initNums(a)) return 0; return deal(table); }};
第四題 621. Task Scheduler
題目描述:
Given a char array representing tasks CPU need to do. It contains capital letters A to Z where different letters represent different tasks.Tasks could be done without original order. Each task could be done in one interval. For each interval, CPU could finish one task or just be idle.
However, there is a non-negative cooling interval n that means between two same tasks, there must be at least n intervals that CPU are doing different tasks or just be idle.
You need to return the least number of intervals the CPU will take to finish all the given tasks.
類比CPU的作業調度機制,有兩個約束條件,一個是要使得總的消耗的CPU單位時間最小,二個是每一個作業都有一個間隔時間n;
需要保證每一個作業至少隔大於等於n的單位時間後再一次調度,如果沒有一個作業需要調度,用idle來填充輸出;
思路:首先考慮到要使得CPU作業時間最短,即保證idle時間最少,那麼採用的策略就是每一次優先在間隔時間內調度那些需要執行次數比較多的作業,同時,每隔一個周期n之後對需要調度的作業次數重新排序,以便於下一次還能按照所需次數最多的作業優先調度的策略來進行;所以最直觀的一個思路就是使用優先隊列來完成,同時用一個輔助隊列來輔助;
class Solution {public: int leastInterval(vector<char>& tasks, int n) { //先統計每個單詞出現的次數 map<int, int> table; for(int i=0;i<(int)tasks.size();i++) table[tasks[i]-'A']++; priority_queue<int> que; for(auto k=table.begin();k!=table.end();k++) que.push(k->second); table.clear(); //初始設定變數 int ret = 0, interval = n+1; queue<int> tmp; while(!que.empty()){ //這種情況下,之後需要通過interval來計算,所以最好就把interval的減一操作放到迴圈裡面去做 //省得在外層interval為0break之後又要減一變成-1,影響後續操作 while(!que.empty()&&interval){ int val = que.top(); que.pop(); if(val - 1 > 0) tmp.push(val-1); interval--; } //只有在兩個隊列都空掉的時候才考慮增加部分次數 if(tmp.empty() && que.empty()) ret += n+1-interval; //不然需要考慮idle情況,增加所有的次數n+1 else{ ret += n+1; while(!tmp.empty()){ int x = tmp.front(); tmp.pop(); que.push(x); } } interval = n+1; } return ret; }};
總結:
找工作路漫漫,但求不忘初心,回首對得起走過的路。
代碼地址:[luuuyi/leetcode-contest]