若是天天作一道算法題,那是否是天天都在進步?
這個活動是從2019年7月中旬開始的,人數不算多,也就幾個好友和好友的好友,過程當中也會有人由於工做的緣故或其餘緣由放棄,或許將來還會有人離開。javascript
活動的主要形式就是在leetcode刷題,每一個工做日一道題,每週作總結,目前已是第十三期,接下來我會把每期的題作一個總結,因爲我是側重javascript,因此活動中的每道題都是以js語言來實現解題方法。java
活動的規則比較嚴謹,羣裏天天早上10點以前發題,晚上10點審覈,審覈有管理員專門審覈,稱爲打卡,沒有打卡的人,須要發紅包給管理員做爲天天統計費用。算法
活動的目的就是培養算法思惟,瞭解常見的算法,好比分治算法、貪心算法、動態優化等等。數組
微信公衆號驚天碼盜同步。bash
上期回顧:
微信
對於非負整數 X 而言,X 的數組形式是每位數字按從左到右的順序造成的數組。例如,若是 X = 1231,那麼其數組形式爲 [1,2,3,1]。app
給定非負整數 X 的數組形式 A,返回整數 X+K 的數組形式。性能
示例 1:優化
輸入:A = [1,2,0,0], K = 34
輸出:[1,2,3,4]
解釋:1200 + 34 = 1234複製代碼
示例 2:ui
輸入:A = [2,7,4], K = 181
輸出:[4,5,5]
解釋:274 + 181 = 455
複製代碼
示例 3:
輸入:A = [2,1,5], K = 806
輸出:[1,0,2,1]
解釋:215 + 806 = 1021複製代碼
示例 4:
輸入:A = [9,9,9,9,9,9,9,9,9,9], K = 1
輸出:[1,0,0,0,0,0,0,0,0,0,0]
解釋:9999999999 + 1 = 10000000000複製代碼
提示:
1 <= A.length <= 10000
0 <= A[i] <= 9
0 <= K <= 10000
若是 A.length > 1
,那麼 A[0] != 0
題解:
思路1:逐位相加法
逐位相加須要判斷狀況,咱們如今有兩種狀況,一種是數組A的長度大於K,可使用逐位相加法;另外一種狀況是數組的長度小於K,能夠把數組轉化成數字計算,而後再轉成數組。(這個方法感受比較笨,不是一個很好的解題方法)
執行用時:168ms;內存消耗:40.5MB;
var addToArrayForm = function(A, K) {
let len=A.length;
let list=[];
let num=K;
let count=len-1;
if(len>=(K+'').length){//數組的長度大於K
while(count>=0){
num+=A[count];
if(count==0){
if(num>=10){
list.push(num%10);
list.push(1);
}else{
list.push(num%10);
}
}else{
list.push(num%10);
}
num=Math.floor(num /10)
count--
}
list= list.reverse()
}else{//數組的長度小於K
list=String(Number(A.join(''))+K).split('')
}
return list
};
複製代碼
思路2:數組相加法
把數字轉化爲數組,進行兩個數組的相加,進的狀況特殊處理;
執行用時:248ms;內存消耗:41.4MB;
var addToArrayForm = function(A, K) {
let B=String(K).split('').map(i=>+i);
A.reverse();
B.reverse();
const maxLength=Math.max(A.length,B.length);
for(var i=0; i<maxLength;i++){
const sum=(A[i]||0)+(B[i]||0);
if(sum<=9){
A[i]=sum;
}else{
A[i]=sum-10;
A[i+1]=A[i+1]?A[i+1]+1:1;
}
}
return A.reverse()
};
複製代碼
給定長度爲 2n 的數組, 你的任務是將這些數分紅 n 對, 例如 (a1, b1), (a2, b2), ..., (an, bn) ,使得從1 到 n 的 min(ai, bi) 總和最大。
示例 1:
輸入: [1,4,3,2]
輸出: 4
解釋: n 等於 2, 最大總和爲 4 = min(1, 2) + min(3, 4).複製代碼
提示:
一、n 是正整數,範圍在 [1, 10000].
2、數組中的元素範圍在 [-10000, 10000].
題解:
思路1:取餘法
排序,取偶;這個題比較簡單;
執行用時:192ms;內存消耗:38.7MB;
var arrayPairSum = function(nums) {
let list=nums.sort((a,b)=>a-b);
let num=0;
list.forEach((item,i)=>{
if(i%2==0){
num+=item
}
})
return num
};
複製代碼
思路2:跳針法
排序,循環跳針;
執行用時:288ms;內存消耗:38.9MB;
var arrayPairSum = function(nums) {
let list=nums.sort((a,b)=>a-b);
let num=0;
for(let i=0;i<nums.length;i+=2){
num+=list[i]
}
return num
};
複製代碼
你總共有 n 枚硬幣,你須要將它們擺成一個階梯形狀,第 k 行就必須正好有 k 枚硬幣。
給定一個數字 n,找出可造成完整階梯行的總行數。
n 是一個非負整數,而且在32位有符號整型的範圍內。
示例 1:
n = 5
硬幣可排列成如下幾行:
¤
¤ ¤
¤ ¤
由於第三行不完整,因此返回2.複製代碼
示例 2:
n = 8
硬幣可排列成如下幾行:
¤
¤ ¤
¤ ¤ ¤
¤ ¤
由於第四行不完整,因此返回3.複製代碼
題解:
思路1:數學公式法
能用數學公式解決的,必定能夠經過代碼解決;
執行用時:108ms;內存消耗:36.1MB;
var arrangeCoins = function(n) {
return Math.floor(Math.sqrt(2*n+0.25)-0.5);
};
複製代碼
思路2:遞增法
像這種線性遞增,規律太明顯,能夠用條件法或循環來解決,當累加得值大於給定的n時,返回上個行數;
執行用時:120ms;內存消耗:36MB;
var arrangeCoins = function(n) {
let i = 0,sum = 0;
while (++i) {
sum += i;
if (sum > n) return i - 1;
}
}
複製代碼
給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。
若是你最多隻容許完成一筆交易(即買入和賣出一支股票),設計一個算法來計算你所能獲取的最大利潤。
注意你不能在買入股票前賣出股票。
示例 1:
輸入: [7,1,5,3,6,4]
輸出: 5
解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 5 天(股票價格 = 6)的時候賣出,最大利潤 = 6-1 = 5 。
注意利潤不能是 7-1 = 6, 由於賣出價格須要大於買入價格。複製代碼
示例 2:
輸入: [7,6,4,3,1]
輸出: 0
解釋: 在這種狀況下, 沒有交易完成, 因此最大利潤爲 0。複製代碼
題析:這道題能夠簡化爲求數組中兩點之差的問題,你也能夠理解爲在x軸上求間距問題;在leetcode的題解上有人提到用牛頓萊布尼茨公式來解決此類問題;最終優化後的代碼如同思路1。
這道題很容易形成一個問題就是內存溢出,算法裏的參數,是動態生成的隨機數,他有不少種可能,就拿目前的題來講,我陷入了一個錯誤的區域,就是用數組來存儲差值,而後取數組最大值。當參數無窮長的時候,內存就會嚴重不足。因此不少看似沒有問題的代碼,其實也不是那麼完美。
可是用變量來存儲數據,就不會出現以上問題;關於用變量存儲是怎麼解決的,思路有不少了。
題解:
思路1:比差法
用一個變量來保存差值,用另外一個來保存最小值;在循環中,若是遇到當前值大於最小值,就取最大的差值;若是小於就修改最小值。這是目前主要的思路。
執行用時:76ms;內存消耗:35.4MB;
var maxProfit = function(prices) {
let curMin = prices[0];
let sum = 0
for (let i=0;i<prices.length;i++) {
if (prices[i] < curMin) {
curMin = prices[i]
continue;
}
sum = Math.max(prices[i] - curMin, sum)
}
return sum
}
複製代碼
思路2:冒泡對比法
用兩個循環來執行,用數組中的每一位和他後面的數比差;而後取最大值。可是時間複雜度會很大,影響性能。
執行用時:996ms;內存消耗:35.3MB;
var maxProfit = function(prices) {
let temp=null;
for(let i=0; i<prices.length-1;i++){
for(let j=i+1;j<prices.length;j++){
const num=prices[j]-prices[i];
if(num>temp){
temp=num
}
}
}
return temp
}
複製代碼
給定兩個字符串形式的非負整數 num1
和num2
,計算它們的和。
注意:
1.num1
和num2
的長度都小於 5100.
2.num1
和num2
都只包含數字 0-9
.
3.num1
和num2
都不包含任何前導零。
4.你不能使用任何內建 BigInteger 庫, 也不能直接將輸入的字符串轉換爲整數形式。
題解:
思路1:雙指針法
經過兩個字符串的索引,逐一遞減,如遇進一存在temp中,如遇短的字符串無值的時候,用0補位;須要注意的是最後的判斷條件,若是最後須要進一則特殊處理;
執行用時:104ms;內存消耗:36.8MB;
var addStrings = function(num1, num2) {
let i=num1.length-1;
let j=num2.length-1;
let arr=[];
let temp=0;
while(i>=0||j>=0){
const n1=num1[i]-0||0;
const n2=num2[j]-0||0;
const num=n1+n2+temp;
temp=num/10>=1?1:0;
arr.push(num%10)
i--; j--;
if(i<0&&j<0&&temp)arr.push(1);
}
return arr.reverse().join('')
};
複製代碼
思路2:取長補短法
找到長的哪個字符串,把短的字符串,用0填充,而後循環相加,判斷是否進一;特殊處理。
執行用時:104ms;內存消耗:36.8MB;
var addStrings = function(num1, num2) {
let maxLen=Math.max(num1.length,num2.length);
let minLen=Math.min(num1.length,num2.length)
if(num1.length!=maxLen){
num1=(Array(maxLen-minLen).fill(0).join(''))+num1
}else{
num2=(Array(maxLen-minLen).fill(0).join(''))+num2
}
let arr=Array(maxLen).fill(0);
for(let i=maxLen-1;i>=0;i--){
let num=Number(num1[i])+Number(num2[i]);
arr[i]=arr[i]>0?arr[i]+num:num;
if(i==0&&arr[i]>9){
arr[0]=arr[i]-10
arr.unshift(1)
}
if(i>0&&arr[i]>9){
arr[i]=arr[i]-10
arr[i-1]=1
}
}
return arr.join('')
};
複製代碼
三期結束,但願有更多的小夥伴加入,感謝你們一路的陪伴與堅持。
關注微信公衆號「驚天碼盜」,輸入算法,拉你進羣。