1,两数相加
题目描述:给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
1,首先实现一个链表节点类,如下:
class ListNode {
val: number;
next: ListNode | null;
constructor(val?: number, next?: ListNode | null) {
this.val = val === undefined ? 0 : val;
this.next = next === undefined ? null : next;
}
}
然后实现一个将数组转换为单链表结构的函数如下:
function arrToList(arr: number[]) {
const head = new ListNode();
let temp = head;
arr.forEach((item) => {
temp.next = new ListNode(item);
temp = temp.next;
});
return head.next;
}
链表相加函数:
function addTwoNumbers(
l1: ListNode | null,
l2: ListNode | null
): ListNode | null {
const newListNode = new ListNode();
let cur = newListNode;
let forward = 0;
while (l1 || l2 || forward) {
const firstNum = l1 ? l1.val : 0;
const secondNum = l2 ? l2.val : 0;
const sum = firstNum + secondNum + forward;
const remainder = sum % 10;
forward = sum >= 10 ? 1 : 0;
cur.next = new ListNode(remainder);
cur = cur.next;
l1 = l1 ? l1.next : null;
l2 = l2 ? l2.next : null;
}
return newListNode.next;
}
具体调试代码链接请看:stackblitz.com/edit/typesc…
2,三数相加为0
题目描述如下题目
用到的方法是排序+双指针,首先将数组由小到大进行排序,然后针对a进行遍历,b和c作为双指针进行移动,左指针向右移动,右指针向左移动,注意边界条件即可,代码如下:
const set = new Set<number[]>();
const len = nums.length;
// 排序
nums.sort((a, b) => a - b);
for (let i = 0; i < len; i++) {
// 遍历,如果a都大于0了。那么直接返回
if (nums[i] > 0) break;
// 过滤掉重复的数据
if (i > 0 && nums[i] === nums[i - 1]) continue;
let left = i + 1;
let right = len - 1;
while (left < right) {
// 指针进行移动
if (nums[i] + nums[left] + nums[right] === 0) {
set.add([nums[i], nums[left], nums[right]]);
// 指针左右移动
left++;
right--;
// 去除重复的数据
while (left < right && nums[left] === nums[left - 1]) left++;
while (left < right && nums[right] === nums[right + 1]) right--;
} else if (nums[i] + nums[left] + nums[right] < 0) {
left++;
} else {
right--;
}
}
}
return Array.from(set);
}
3,最接近的三数之和
题目描述如下:
此题与上述第二题,三数之和非常类似,也可以用上述描述的双指针方法来做,代码如下:
function threeSumClosest(nums: number[], target: number): number {
const len = nums.length;
nums.sort((a, b) => a - b);
// 存储最好的结果
let current = 100000;
for (let i = 0; i < len; i++) {
// 去除重复的数据
if (i > 0 && nums[i] === nums[i - 1]) continue;
let left = i + 1;
let right = len - 1;
// 双指针移动
while (left < right) {
const sum = nums[left] + nums[right] + nums[i];
if (sum === target) {
// 如果等于目标值了,直接返回
return sum;
}
if (Math.abs(current - target) > Math.abs(sum - target)) {
// 判断是否比原有的值更接近目标值
current = sum;
}
if (sum - target > 0) {
right = right - 1;
// 右指针移动,同时去除重复的数据
while (left < right && nums[right] === nums[right + 1]) right--;
} else {
left = left + 1;
// 左指针移动,同时去除重复数据
while (left < right && nums[left - 1] === nums[left]) left++;
}
}
}
return current;
}