1.快樂數
題目:
編寫一個算法來判斷一個數 n 是不是快樂數。
「快樂數」定義爲:對於一個正整數,每一次將該數替換爲它每個位置上的數字的平方和,然後重複這個過程直到這個數變爲 1,也可能是 無限循環 但始終變不到 1。如果 可以變爲 1,那麼這個數就是快樂數。
如果 n 是快樂數就返回 True ;不是,則返回 False 。
思路:重點就是無限循環,這個就和環形鏈表很像了。環形鏈表的終止條件是節點爲null,或者循環,這個的終止條件是1,或者循環。所以也是兩種解法:雙指針法和map法,
map:
/**
* @param {number} n
* @return {boolean}
*/
var isHappy = function(n) {
if (n == 1) return true;
const set = new Set();
let k;
while (!set.has(n)) {
let sum = 0;
k = n;
while (n) {
let value = n % 10;
sum += value * value;
n = (n / 10) | 0;
}
if (sum == 1) return true;
set.add(k);
n = sum;
}
return false;
};
雙指針:
var isHappy = function(n) {
let slow = sum(n)
let fast = sum(slow)
while(slow != fast){
slow = sum(slow)
fast = sum(sum(fast))
}
return slow == 1
}
function sum(n){
n = n + ''
let sum = 0
for(let num of n){
sum += num * num
}
return sum
}
2.移除鏈表元素
題目:刪除鏈表中等於給定值 val 的所有節點。
思路:循環遍歷節點,如果該節點的下一個節點的val是目標值,就把該節點的next指向下個節點的next
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} val
* @return {ListNode}
*/
var removeElements = function(head, val) {
while (head && head.val == val) {
head = head.next;
}
let node = head;
while (node && node.next) {
if (node.next.val === val) {
node.next = node.next.next;
} else {
node = node.next;
}
}
return head;
};
3.計數質數
題目:統計所有小於非負整數 n 的質數的數量。
思路:首先,我們從2開始,判斷某個數是否爲質數,然後將它小於n且是該值的倍數的數直接忽略,如果都不是前面某個數的倍數,那麼該數肯定是質數
/**
* @param {number} n
* @return {number}
*/
var countPrimes = function (n) {
let count = 0
signs = new Array(n+1)
for (let i = 2; i < n; i++) {
if (!signs[i]) {
count++
for (let j = 2 * i; j < n; j += i) {
signs[j] = true
}
}
}
return count
};
4.同構字符串
題目:
給定兩個字符串 s 和 t,判斷它們是否是同構的。
如果 s 中的字符可以被替換得到 t ,那麼這兩個字符串是同構的。
所有出現的字符都必須用另一個字符替換,同時保留字符的順序。兩個字符不能映射到同一個字符上,但字符可以映射自己本身。
思路:,首先,對字符串的字母,我們可以轉換成出現順序的數字排列。比如,'ab'轉換爲'01','aaba'換換位'0010',如果轉換之後的兩個字符串相等就是同構,如果不相等就不是同構
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var aaa = (s) => {
const res = [];
let v = "";
for (let i = 0, l = s.length; i < l; i++) {
if (res.includes(s[i])) {
v += res.indexOf(s[i]);
} else {
v += res.length;
res.push(s[i]);
}
}
return v;
};
var isIsomorphic = function (s, t) {
return aaa(s) === aaa(t);
};
優化:類似的思路,左邊的字母和右邊的字母有一一對應的關係,一個字母只能有一個映射,且左右均唯一。
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var isIsomorphic = function (s, t) {
const map = {};
const res = [];
for (let i = 0, l = s.length; i < l; i++) {
if (!map[s[i]] && !res.includes(t[i])) {
map[s[i]] = t[i];
res.push(t[i]);
} else {
if (map[s[i]] && map[s[i]] !== t[i]) return false;
if (!map[s[i]] && res.includes(t[i])) return false;
}
}
return true;
};
5.反轉鏈表
題目:反轉一個單鏈表。
思路:首先是迭代。聲明一個額外的變量存放結果,遍歷鏈表,每次把當前的節點作爲結果的開始節點即可
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function(head) {
let res = null;
let temp;
while (head) {
temp = head.next;
head.next = res;
res = head;
head = temp;
}
return res;
};
遞歸:
每次取出一個節點,然後遞歸操作剩餘節點,將當前節點作爲剩餘節點的next。最終遞歸得到結果
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function (head) {
if (head && head.next) {
let next = head.next;
let reverseHead = reverseList(next);
head.next = null;
next.next = head;
return reverseHead;
} else {
return head;
}
};
尾遞歸:(看到別人的方法)用另一個函數做尾遞歸,思路類似,翻轉每一個節點
var reverseList = function(head) {
if(!head || !head.next) return head
head = reverse(null, head)
return head
};
var reverse = function(prev, curr) {
if(!curr) return prev
var next = curr.next
curr.next = prev
return reverse(curr, next)
};