1.存在重複元素 *簡單
題目:
給定一個整數數組,判斷是否存在重複元素。
如果任意一值在數組中出現至少兩次,函數返回 true
。如果數組中每個元素都不相同,則返回 false
。
思路:首先是用map來記錄
/**
* @param {number[]} nums
* @return {boolean}
*/
var containsDuplicate = function(nums) {
let map={}
for(let i=0,l=nums.length;i<l;i++){
if(map[nums[i]]){
return true
}else{
map[nums[i]]=1
}
};
return false
};
還可以利用Set對象的特點
/**
* @param {number[]} nums
* @return {boolean}
*/
var containsDuplicate = function(nums) {
return new Set(nums).size!==nums.length
};
藉助indexOf方法(這種方法最慢,並且慢得多)
var containsDuplicate = function(nums) {
for(let i=0,l=nums.length;i<l;i++){
if(nums.indexOf(nums[i])!==i)return true
};
return false
};
還是用Set
/**
* @param {number[]} nums
* @return {boolean}
*/
var containsDuplicate = function(nums) {
const set=new Set();
for(let i=0,l=nums.length;i<l;i++){
if(set.has(nums[i]))return true
set.add(nums[i])
};
return false
}
2.存在重複元素 II *簡單
題目:
給定一個整數數組和一個整數 k,判斷數組中是否存在兩個不同的索引 i 和 j,使得 nums [i] = nums [j],並且 i 和 j 的差的 絕對值 至多爲 k。
思路:還是先來簡單的,用map記錄
/**
* @param {number[]} nums
* @param {number} k
* @return {boolean}
*/
var containsNearbyDuplicate = function(nums, k) {
let map = {};
for (let i = 0, l = nums.length; i < l; i++) {
if (map[nums[i]] !== undefined) {
if (i - map[nums[i]] <= k) return true;
}
map[nums[i]] = i;
}
return false;
};
另一個思路:設想一滑動窗口,窗口寬度固定,然後往左滑,判斷新添加的元素是否是k,如果是k且窗口已有,則返回true,如果窗口寬度大於k,則刪除set的第一個元素
/**
* @param {number[]} nums
* @param {number} k
* @return {boolean}
*/
var containsNearbyDuplicate = function(nums, k) {
const set = new Set();
for(let i = 0; i < nums.length; i++) {
if(set.has(nums[i])) {
return true;
}
set.add(nums[i]);
if(set.size > k) {
set.delete(nums[i - k]);
}
}
return false;
};
3.翻轉二叉樹 *簡單
題目:翻轉一棵二叉樹。
思路:遞歸,或者用數組迭代,很簡單,無非是遍歷順序的不同
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
if(root === null) return null;
invertTree(root.left);
invertTree(root.right);
[root.left,root.right] = [root.right,root.left];
return root;
};
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
if (root && (root.left || root.right)) {
let temp = root.left;
root.left = invertTree(root.right);
root.right = invertTree(temp);
}
return root;
};
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
let queue = [root];
while(queue.length > 0){
let cur = queue.pop();
if(cur === null) continue;
[cur.left,cur.right] = [cur.right,cur.left];
queue.unshift(cur.left);
queue.unshift(cur.right);
}
return root;
};
4.兩數相加 *中等
題目:
給出兩個 非空 的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式存儲的,並且它們的每個節點只能存儲 一位 數字。
如果,我們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。
您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。
思路:動態規劃,用尾遞歸的方式實現,按照同樣的順序去遍歷兩個鏈表的每一個節點,如果是null則值爲0,然後後前一位是否要進1
var addTwo = (l1, l2, flag) => {
if (l1 || l2||flag) {
let v1 = 0;
let v2 = 0;
if (l1) {
v1 = l1.val;
l1 = l1.next;
}
if (l2) {
v2 = l2.val;
l2 = l2.next;
}
const v = (flag ? 1 : 0) + v1 + v2;
flag = v > 9;
const cv = new ListNode(v % 10);
cv.next = addTwo(l1, l2, flag);
return cv;
} else {
return null;
}
};
var addTwoNumbers = function (l1, l2) {
return addTwo(l1, l2, false);
};
然後把flag去掉,直接給l1的下一個節點+1,就只需要一個函數遞歸完成
var addTwoNumbers = function (l1, l2) {
if (l1 || l2) {
let v1 = 0;
let v2 = 0;
if (l1) {
v1 = l1.val;
l1 = l1.next;
}
if (l2) {
v2 = l2.val;
l2 = l2.next;
}
const v = v1 + v2;
const flag = v > 9;
if (flag) {
if (l1) {
l1.val += 1;
} else {
l1 = new ListNode(1);
}
}
const cv = new ListNode(v % 10);
cv.next = addTwoNumbers(l1, l2);
return cv;
} else {
return null;
}
};
迭代實現,思路一樣
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
var addTwoNumbers = function (l1, l2) {
let flag = false;
let res = null;
let cur = null;
while (l1 || l2 || flag) {
let v1 = 0;
let v2 = 0;
if (l1) {
v1 = l1.val;
l1 = l1.next;
}
if (l2) {
v2 = l2.val;
l2 = l2.next;
}
const v = (flag ? 1 : 0) + v1 + v2;
flag = v > 9;
const cv = new ListNode(v % 10);
if (!res) {
res = cur = cv;
} else {
cur.next = cv;
cur = cv;
}
}
return res;
};
5.無重複字符的最長子串 *中等
題目:給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。
思路:最簡單的思路,用一個數組記錄之前的字符,二層嵌套的循環,遍歷每一個可能的字符,然後比較最大值
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let stack = [];
let res = 0;
for (let i = 0, l = s.length; i < l; i++) {
for (let j = i; j < l && l - i > res; j++) {
if (stack.includes(s[j])) {
res = stack.length > res ? stack.length : res;
stack = [];
break;
} else {
stack.push(s[j]);
}
}
res = stack.length > res ? stack.length : res;
stack = [];
}
return res;
};
優化:當我們遇到重複的字符串時,找到重複的那個字符的下標,然後從它的下一個下標開始遍歷,這樣就不會重複遍歷了
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let stack = [];
let res = 0;
for (let i = 0, l = s.length; i < l; i++) {
if (stack.includes(s[i])) {
res = stack.length > res ? stack.length : res;
const x = stack.indexOf(s[i]);
stack.splice(0, x + 1);
stack.push(s[i]);
} else {
stack.push(s[i]);
}
}
res = stack.length > res ? stack.length : res;
return res;
};
優化:類用一個map記錄每個字符出現的位置,遇到重複的就比較長度,然後更新該字符的值
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let map = new Map(), max = 0
for(let i = 0, j = 0; j < s.length; j++) {
if(map.has(s[j])) {
i = Math.max(map.get(s[j]) + 1, i)
}
max = Math.max(max, j - i + 1)
map.set(s[j], j)
}
return max
};
6.最長迴文子串 *中等
思路:暴力解法,雙重遍歷,找到最長的那個
/**
* @param {string} s
* @return {string}
*/
var isStr = (s) => {
while (s.length > 1) {
if (s[0] == s[s.length - 1]) {
s = s.substring(1, s.length - 1);
} else {
return false;
}
}
return true;
};
var longestPalindrome = function (s) {
let res = "";
let end = s.length;
for (let i = 0; i < end; i++) {
for (let j = end; j > res.length + i; j--) {
if (isStr(s.substring(i, j))) {
if (j - i > res.length) {
res = s.substring(i, j);
}
}
}
}
return res;
};
優化:動態規劃。
如果一個字符串是迴文串,那麼它去掉首尾兩個字符也是迴文串。同理,一個迴文串如果首尾各擴展1個字符,且擴展的字符相同,那麼新
的字符串也是迴文串
/**
* @param {string} s
* @return {string}
*/
var isStr = (s) => {
while (s.length > 1) {
if (s[0] == s[s.length - 1]) {
s = s.substring(1, s.length - 1);
} else {
return false;
}
}
return true;
};
var longestPalindrome = function (s) {
let res = "";
let end = s.length;
for (let i = 0; i < end; i++) {
for (let j = end; j > res.length + i; j--) {
if (isStr(s.substring(i, j))) {
if (j - i > res.length) {
res = s.substring(i, j);
}
}
}
}
return res;
};
優化:我們用遇到的第一個迴文串向兩邊擴展,同時記錄最長字符串,最後得到結果
/**
* @param {string} s
* @return {string}
*/
var longestPalindrome = function (s) {
let result = s[0] || "";
for (let i = 0; i < s.length; i++) {
for (let j = 1; j <= 2; j++) {
let left = i, right = i + j;
while(left >= 0 && right < s.length && s[left] === s[right]) {
left--, right++;
};
let length = right - left - 1; //(right - 1) - (left + 1) + 1
if (length > result.length) {
result = s.substr(left + 1, length);
}
}
}
return result;
};