Javascript常见算法(三)

 K个一组翻转链表

在JavaScript中,处理链表问题时,通常需要手动实现链表节点的数据结构,并编写相应的函数来操作链表。对于“K个一组翻转链表”的问题,你可以按照以下步骤来实现:

思路

  1. 定义一个哑节点(Dummy Node):哑节点作为链表的头部,其next指针指向原始链表的头节点。哑节点的存在可以简化边界条件的处理,特别是在翻转第一组节点时。

  2. 遍历链表:使用指针(例如prevhead)遍历链表,其中prev指针指向当前要翻转的链表段的前一个节点,head指针指向当前要翻转的链表段的头节点。

  3. 检查剩余节点数:在每次翻转之前,通过遍历来检查剩余节点数是否足够K个。如果不足K个,则无需翻转,直接返回当前链表。

  4. 翻转链表段:使用辅助函数翻转从headtail.prev(不包括tail)的链表段,并返回翻转后的新头节点和新尾节点。注意,这里的tail是原始链表中第K个节点的下一个节点,即翻转后链表段的下一个节点。

  5. 连接翻转后的链表段:将翻转后的链表段通过prev.next连接到原链表上,并更新prevhead为下一组要翻转的链表段的起始位置。

  6. 重复步骤2-5,直到遍历完整个链表。

  7. 返回结果:最终返回哑节点的next指针,即翻转后的链表头节点(如果原始链表为空,则返回null)。

下面是一个可能的实现:

class ListNode {  
    constructor(val = 0, next = null) {  
        this.val = val;  
        this.next = next;  
    }  
}  
  
function reverseKGroup(head, k) {  
    if (!head || k === 1) return head;  
  
    let dummy = new ListNode(0); // 创建一个哑节点,方便处理头节点  
    dummy.next = head;  
    let prev = dummy; // prev用于连接翻转后的链表段  
  
    while (head) {  
        let tail = prev; // tail用于记录当前需要翻转链表的最后一个节点的前一个节点  
        // 检查剩余节点是否足够k个  
        for (let i = 0; i < k; i++) {  
            tail = tail.next;  
            if (!tail) {  
                // 如果不足k个,则直接返回结果  
                return dummy.next;  
            }  
        }  
  
        // 翻转前k个节点  
        let nextGroup = tail.next; // 记录下一组的头节点  
        let [newHead, newTail] = reverse(head, tail); // 翻转并返回新的头尾节点  
          
        // 将翻转后的链表段连接到原链表上  
        prev.next = newHead;  
        newTail.next = nextGroup;  
  
        // 更新prev和head为下一组的开始  
        prev = newTail;  
        head = nextGroup;  
    }  
  
    return dummy.next;  
}  
  
// 翻转链表从head到tail.prev  
function reverse(head, tail) {  
    let prev = tail.next;  
    let curr = head;  
    while (prev !== tail) {  
        let nextTemp = curr.next;  
        curr.next = prev;  
        prev = curr;  
        curr = nextTemp;  
    }  
    return [prev, head];  
}  
  
// 示例用法  
let head = new ListNode(1);  
head.next = new ListNode(2);  
head.next.next = new ListNode(3);  
head.next.next.next = new ListNode(4);  
head.next.next.next.next = new ListNode(5);  
  
let result = reverseKGroup(head, 2);  
// 打印翻转后的链表值  
let curr = result;  
while (curr) {  
    console.log(curr.val);  
    curr = curr.next;  
}  
// 输出应为: 2 1 4 3 5

 

删除排序数组中的重复项

在原数组改:

要在原地删除排序数组中的重复项,并且只使用O(1)的额外空间,你可以使用双指针的方法。这种方法中,一个指针(我们称之为slow)用于追踪不重复元素应该放置的位置,另一个指针(我们称之为fast)用于遍历数组。

以下是具体的算法步骤:

  1. 初始化两个指针slowfast,都指向数组的第一个元素。
  2. 遍历数组(fast指针从第二个元素开始),比较arr[slow]arr[fast]的值。
  3. 如果arr[slow]不等于arr[fast],说明找到了一个新的不重复的元素,将arr[fast]的值复制到arr[slow+1](因为slow指向的是当前不重复序列的最后一个元素),然后slowfast都向前移动一位。
  4. 如果arr[slow]等于arr[fast],说明遇到了重复元素,只移动fast指针。
  5. 重复步骤2-4,直到fast指针到达数组的末尾。
  6. slow + 1就是移除重复项后数组的新长度(因为slow是从0开始的索引,所以实际长度需要加1)。

下面是相应的JavaScript代码实现:

function removeDuplicates(nums) {  
    if (nums.length === 0) {  
        return 0;  
    }  
      
    let slow = 0;  
    for (let fast = 1; fast < nums.length; fast++) {  
        if (nums[slow] !== nums[fast]) {  
            slow++;  
            nums[slow] = nums[fast];  
        }  
    }  
      
    return slow + 1;  
}  
  
// 示例  
let nums = [1,1,2,2,3];  
let newLength = removeDuplicates(nums);  
console.log(newLength); // 输出: 3  
console.log(nums); // 输出: [1, 2, 3]

 新的数组(内置API)

1. 使用Set和扩展运算符(...

Set是ES6引入的一种新的数据结构,它类似于数组,但是成员的值都是唯一的,没有重复的值。因此,我们可以利用Set的这个特性来去除数组中的重复项。

let arr = [1, 2, 2, 3, 4, 4, 5];  
let uniqueArr = [...new Set(arr)];  
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]
2. 使用filter()方法

filter()方法创建一个新数组,其包含通过所提供函数实现的测试的所有元素。我们可以利用这个特性,结合indexOf()方法来检查元素是否首次出现。

let arr = [1, 2, 2, 3, 4, 4, 5];  
let uniqueArr = arr.filter((item, index, self) => {  
    return self.indexOf(item) === index;  
});  
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]
3. 使用Map对象

类似于SetMap对象也可以用来存储键值对,其中键是唯一的。我们可以利用这个特性,将数组的值作为键存储到Map中,然后提取出Map的键来形成一个没有重复元素的数组。

let arr = [1, 2, 2, 3, 4, 4, 5];  
let map = new Map();  
arr.forEach(item => map.set(item, true));  
let uniqueArr = Array.from(map.keys());  
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]
4. 使用reduce()方法

reduce()方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。我们可以利用这个特性来累加不重复的元素。

let arr = [1, 2, 2, 3, 4, 4, 5];  
let uniqueArr = arr.reduce((acc, current) => {  
    if (acc.indexOf(current) === -1) acc.push(current);  
    return acc;  
}, []);  
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值