SOURCE

//快慢指针:两个指针同向移动,但步长不同。适用场:判断链表是否有环、寻找链表中点、删除倒数第N个节点

//对撞指针:两个指针从序列两端出发,​相向移动,直至碰面。适用场景:有序数组的两数之和、反转字符串、回文判断

//滑动窗口:两个指针作为窗口的左右边界,​同向移动以维护一个连续区间。适用场景:最小覆盖子串、无重复字符的最长子串、长度最小的子数组

//-------判断链表是否有环:快慢指针----

/*
在拿到这道题的时候,完全是看不懂的,链表是个啥比较抽象的东西,问了AI,把链表具象化为js代码,链表就是一个构造函数,里面定义了节点对象。

在js中,链表是通过对象来实现的。每个节点都是一个独立的对象,包含val属性存储数据,和next属性指向下一个节点
。而head是一个变量,它保存着第一个节点对象的内存地址引用*/

//构造函数,定义了每个链表节点对象应该有哪些属性
function ListNode(val) {
 this.val = val;
 this.next = null
}
var hasCycle = function(head) {
    if(head==null || head.next === null){
        return false
    }
    let slow=head;
    let fast=head;
    while(fast!=null || fast.next!==null) {
        slow=slow.next //慢指针每次移动1步
        fast=fast.next.next //快指针每次移动 2 步
        if(slow==fast) {
            return true //指针相遇,表明有环
        }
    }
    
    return false
    
};

//使用 new关键字调用构造函数,​创建一个具体的节点对象
let node1 = new ListNode(1)
let node2 = new ListNode(2)
let node3 = new ListNode(3)
let node4 = new ListNode(4)
let node5 = new ListNode(5)
node1.next = node2
node2.next = node3;
node3.next = node4;
node4.next = node5;
node5.next = node2; // 形成环

console.log(hasCycle(node1)); // 输出:true

node5.next = null; //无环
console.log(hasCycle(node1)); // 输出:false

//------------反转字符串:对撞指针---------
var reverseString = function(s) {
    let left = 0, right = s.length - 1;
    while (left < right) {
        // 传统方法:使用临时变量
       //let temp = s[left];
       //s[left] = s[right];
       //s[right] = temp;
        // 解构赋值,交换两个变量,交换左右指针所指的字符
        [s[left], s[right]] = [s[right], s[left]];
        left++;
        right--;
    }
    return s; 
};

// 示例
let arr = ["h","e","l","l","o"];
reverseString(arr);
console.log(arr); // 输出: ["o","l","l","e","h"]



//------------给定一个字符串s,请找出其中不含有重复字符的最长子串的长度:滑动窗口---------
/*
滑动窗口算法通过维护一个窗口(通常由左右指针 left和 right定义),动态调整窗口大小来寻找最优解
其基本逻辑是右指针 right用于扩展窗口,左指针 left用于收缩窗口
*/

var lengthOfLongestSubstring = function(s) {
    let left = 0;
    let maxLength = 0;
    const charSet = new Set(); // 使用Set存储当前窗口中的字符,保证唯一性

    // 右指针向右遍历
    for (let right = 0; right < s.length; right++) {
        const currentChar = s[right];

        // 如果当前字符已在窗口中(即出现重复)
        while (charSet.has(currentChar)) {
            // 不断收缩左边界,直到移除那个重复的字符
            charSet.delete(s[left]);
            left++;
        }

        // 将当前字符加入窗口
        charSet.add(currentChar);
        // 更新最大长度 (right - left + 1 是当前窗口长度)
        maxLength = Math.max(maxLength, right - left + 1);
    }

    return maxLength;
};

console.log(lengthOfLongestSubstring("abcabcbb")); // 输出: 3 ("abc")
console.log(lengthOfLongestSubstring("pwwkew")); // 输出: 3 ("wke")
console 命令行工具 X clear

                    
>
console