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)
};