1.路徑總和
題目:
給定一個二叉樹和一個目標和,判斷該樹中是否存在根節點到葉子節點的路徑,這條路徑上所有節點值相加等於目標和。
說明: 葉子節點是指沒有子節點的節點。
思路:遞歸遍歷所有節點,然後判斷是否有和目標值相同的成員。
var hasPS = (node, sum, currtS = 0) => {
if (!node) return false;
currtS += node.val;
if (!node.left && !node.right) {
return currtS === sum;
}
return hasPS(node.left, sum, currtS) || hasPS(node.right, sum, currtS);
};
var hasPathSum = function (root, sum) {
if (!root) return false;
return hasPS(root, sum);
};
這個是遞加的思路,。其實遞減的思路是一樣的,並且還不需要聲明另一方法
var hasPathSum = function (root, sum) {
if (!root) return false;
sum -= root.val;
if (!root.left && !root.right) {
return !sum;
}
return hasPathSum(root.left, sum) || hasPathSum(root.right, sum);
};
有遞歸就有循環,來看一下循環的實現,其實就是用對象的形式保存了當前的節點以及該節點對應的剩餘值。如果實現過深拷貝的可能知道,這個方式和深拷貝的做法很像。
var hasPathSum = function (root, sum) {
if (!root) return false
let stack = []
stack.push({
root: root,
sum: root.val
})
while (stack.length) {
let node = stack.pop()
if (!node.root.left && !node.root.right) {
if (node.sum === sum) return true
}
if (node.root.left) {
stack.push({
root: node.root.left,
sum: node.sum + node.root.left.val
})
}
if (node.root.right) {
stack.push({
root: node.root.right,
sum: node.sum + node.root.right.val
})
}
}
return false
};
2.楊輝三角
題目:給定一個非負整數 numRows,生成楊輝三角的前 numRows 行。
思路:和斐波那契數列很像。用前一輪的結果計算下一輪的結果。所以我們只需要設定前幾項的結果,然後遍歷去計算就行。
var generate = function(numRows) {
if (!numRows) return [];
if (numRows === 1) return [[1]];
var res = [[1]];
while (numRows > 1) {
const item = res[res.length - 1];
const v = [];
item.forEach((t, i) => {
if (i) {
v.push(item[i - 1] + t);
} else {
v.push(1);
}
});
v.push(1);
res.push(v);
numRows--;
}
return res
};
3.楊輝三角 II
題目:給定一個非負索引 k,其中 k ≤ 33,返回楊輝三角的第 k 行。
思路:首先,我們可以確定,楊輝三角是左右對稱的,第k行有k+1個成員,所以對第k行,我們只需要計算前Math.ceid(k+1/2)項的結果。
然後,我們用遞歸實現,一個參數表示當前第幾行,另一個參數表示前一輪的結果。
var getNext = (last, row) => {
if (!row) return last;
if (!last) last = [];
var v = [],
l = last.length,
t = Math.floor(l / 2) + 1;
for (let i = 0; i < t; i++) {
v[i] = v[l - i] = !i ? 1 : last[i - 1] + last[i];
}
return getNext(v, row - 1);
};
var getRow = function (rowIndex) {
return getNext(null, rowIndex+1);
};
4.買賣股票的最佳時機
題目:
給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。
如果你最多隻允許完成一筆交易(即買入和賣出一支股票一次),設計一個算法來計算你所能獲取的最大利潤。
注意:你不能在買入股票前賣出股票。
思路:聲明兩個變量,一個裝最大值,一個裝最小值。單次遍歷,每次更新最大值和最小值,最後得到最大值和最小值。
這裏有個問題,就是最大值和最小值的順序問題,所以我們在更新最小值時,也要更新最大值。然後每次更新最大值時,要和之前的最大值比較
var maxProfit = function(prices) {
let l = prices.length;
if (l < 2) return 0;
let min = Infinity,
max = -Infinity,
res = 0;
for (let i = 0; i < l; i++) {
if (prices[i] > max) {
max = prices[i];
res = Math.max(max - min, res);
}
if (prices[i] < min) {
min = max = prices[i];
}
}
return res;
};
問題:變量太多,可以適當減少
優化方向:最大值不需要用一個變量記錄,循環的時候,每次取到的值和當前的最小值比較即可,大於的話計算差,然後和最大值比較。
var maxProfit = function(prices) {
var res = 0;
var min = Infinity;
prices.forEach((i) => {
if (i < min) {
min = i;
} else {
if (i > min) {
res = Math.max(res, i - min);
}
}
});
return res;
};
5.買賣股票的最佳時機 II
題目:
給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。
設計一個算法來計算你所能獲取的最大利潤。你可以儘可能地完成更多的交易(多次買賣一支股票)。
注意:你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。
思路:其實這題想清楚了就很簡單,最重要的是思路。
因爲可以進行多次交易,所以每次只需要和上一項的值比較即可,。如果比上一項的值大,就累加差,如果更小,就不變。
股票的最大收益其實就是相鄰兩項差的正值之和
var maxProfit = function(prices) {
let res = 0,
a = prices[0];
prices.forEach((i) => {
if (i > a) res += i - a;
a = i;
});
return res;
};
6.驗證迴文串
題目:
給定一個字符串,驗證它是否是迴文串,只考慮字母和數字字符,可以忽略字母的大小寫。
說明:本題中,我們將空字符串定義爲有效的迴文串。
思路:先取出所有的數字及字母字符串,然後遍歷新的字符串,看一下某下標和鏡像下標的值是否相等
var isPalindrome = function(s) {
const l = s.length;
if (l < 2) return true;
const a = s.replace(/\W|_/g, "");
let v = 0,
b = 0;
for (let i = 0, s = Math.ceil(a.length / 2); i < s; i++) {
v = Number(a[i]);
b = Number(a[a.length - 1 - i]);
if (!Number.isNaN(v) && !Number.isNaN(b)) {
if (v !== b) return false;
} else if (Number.isNaN(v) && Number.isNaN(b)) {
v = a.charCodeAt(i);
b = a.charCodeAt(a.length - 1 - i);
if (!(v === b || v === b + 32 || v === b - 32)) return false;
} else {
return false;
}
}
return true;
};
問題:比較太多,且分類太多,對於字符串用了unicode值去比較,流程繁瑣
優化方向:先全部轉換爲小寫字符,直接比較
var isPalindrome = function(s) {
const l = s.length;
if (l < 2) return true;
const a = s.replace(/\W|_/g, "").toLowerCase();
for (let i = 0, s = a.length / 2; i < s; i++) {
if (a[i] !== a[a.length - 1 - i]) return false;
}
return true;
};
7.只出現一次的數字
題目:
給定一個非空整數數組,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。
說明:
你的算法應該具有線性時間複雜度。 你可以不使用額外空間來實現嗎?
思路:先來最簡單的吧
var singleNumber = function(nums) {
return nums.find(i=>nums.filter(item=>item===i).length==1)
};
問題:其實重複遍歷了很多次,談不上算法,只能說是解法
優化方向:用一個對象記錄某個數是否出現,沒有出現就累加,出現過就減,最終的結果就是隻出現一次的數
var singleNumber = function(nums) {
let map = {};
let res = 0;
nums.forEach((i) => {
if (map[i] === undefined) {
res += i;
map[i] = 1;
} else {
res -= i;
}
});
return res;
};
優化方向:位運算中的異或。
a^0=a,a^a=0.
所以累計異或即可
var singleNumber = function(nums) {
return nums.reduce((res,i)=>res^i)
};