Javascript-leetcode解法——双指针篇

双指针,大体可以分为三种指针:

1、普通双指针:同向双指针(其实也就是双层for循环

2、对撞双指针:反方向双指针

3、快慢双指针:步调不一致的指针

27.移除元素

思路:首先数组的内存空间地址是连续的,不能单独删除某个元素,只能覆盖

题目要求只返回删了几个元素

采用快慢双指针法, 慢指针负责遍历原数组所有元素,快指针负责记录删除后的新数组

/**
 * @param {number[]} nums
 * @param {number} val
 * @return {number}
 */
var removeElement = function(nums, val) {
let k = 0;
    for(let i = 0;i < nums.length;i++){
        if(nums[i] != val){
            nums[k] = nums[i];
            k++;
        }
    }
    return k
}; //时间复杂度O(n),空间复杂度O(1)

344.反转字符串

思路:对撞双指针,交换值即可

let j = s.length - 1;
    let left = 0, right = 0;
    for (i = 0; i < j; i++) {
        left = s[i];
        right = s[j];
        s[i] = right;
        s[j] = left;
        j--;
    }
    return s

 151.反转字符串中的单词

思路:直接利用js的内置API,暴力解决

  • .split(/\s+/) 意味着【 包括制表符,换行符,回车符,垂直制表符,换页符在内的一个至无穷个类空格字符】隔开。
/**
 * @param {string} s
 * @return {string}
 */
var reverseWords = function (s) {
    s = s.split(/\s+/).reverse().join(" ").trim()
    return s
};

206.反转链表

思路:依次改变node的指向即可。

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function (head) {
    let pre = null, tmp = null, cur = head; 
    if (!head || !head.next) return head;
    while (cur) {

        tmp = cur.next;
        cur.next = pre;
        pre = cur;
        cur = tmp;
    }
    return pre
};

19.删除链表的倒数第N个节点

思路:快慢指针,以快指针的指向为null时结束循环。快指针应比慢指针快走n+1步,以便删除节点。

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {
    const ret = new ListNode(0,head);
    let fast = ret, slow = ret;
    while(n--) {
        fast = fast.next;
    }
    while(fast.next != null) {
        fast = fast.next;
        slow = slow.next;
    }
    slow.next = slow.next.next;
    return ret.next;
};

02.07. 链表相交

思路:注意,找链表相交值是找引用的相交值。

取两条链表的长度差,对齐末尾,查找是否有相等的值。

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
var getListLen = function(head) {
    let len = 0, cur = head;
    while(cur) {
       len++;
       cur = cur.next;
    }
    return len;
}
var getIntersectionNode = function(headA, headB) {
    let curA = headA,curB = headB,
        lenA = getListLen(headA),   // 求链表A的长度
        lenB = getListLen(headB);  
    if(lenA < lenB) {       // 让curA为最长链表的头,lenA为其长度
    
        // 交换变量注意加 “分号” ,两个数组交换变量在同一个作用域下时
        // 如果不加分号,下面两条代码等同于一条代码: [curA, curB] = [lenB, lenA]
        
        [curA, curB] = [curB, curA];
        [lenA, lenB] = [lenB, lenA];
    }
    let i = lenA - lenB;   // 求长度差
    while(i-- > 0) {       // 让curA和curB在同一起点上(末尾位置对齐)
        curA = curA.next;
    }
    while(curA && curA !== curB) {  // 遍历curA 和 curB,遇到相同则直接返回
        curA = curA.next;
        curB = curB.next;
    }
    return curA;
};

142.环形链表II 

思路:快慢指针,如果有环必相遇

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var detectCycle = function (head) {
    if (!head || !head.next) return null;
    let slow = head.next, fast = head.next.next;
    while (fast && fast.next) {
        slow = slow.next;
        fast = fast.next.next;
        if (fast === slow) {
            slow = head;
            while (slow != fast) {
                slow = slow.next;
                fast = fast.next;
            }
            return slow;
        }
    }
    return null;

};

15.三数之和

思路:重点在于去重,先给原数组排序,如果排到某一组数的第一个元素大于0,则可以直接退出循环,减少内存。锁定一个数后,另外两个用对撞双指针即可。

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
        nums = nums.sort((a, b) => a - b);
    let newArr = [];
    for (i = 0; i < nums.length; i++) {
        if (nums[i] > 0) {
            break;
        }
        if (i > 0 && nums[i] === nums[i - 1]) continue; //去重
        let L = i + 1,
            R = nums.length - 1;
        while (L < R) {
            let sum = nums[i] + nums[L] + nums[R];
            if (sum === 0) {
                newArr.push([nums[i], nums[L], nums[R]]);
                while (nums[L] === nums[L + 1]) { L++; } //去重
                while (nums[R] === nums[R - 1]) { R--; } //去重
                L++;
                R--;
                
            }
            else if (sum > 0) { R-- }
            else if (sum < 0) { L++ }

        }


    }
    return newArr
};

18.四数之和 

思路:其实和三数之和一样,其实N数之和都一样,都能用双指针法把原来的O(n^n)降复杂度为O(n^n-1)。

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[][]}
 */
var fourSum = function(nums, target) {
    nums = nums.sort((a, b) => a - b);
    const len = nums.length;
    let newArr = [];
    for (i = 0; i < len; i++) {
        if (i > 0 && nums[i] === nums[i - 1]) continue;
        for (j = i + 1; j < len; j++) {
            if (j >i + 1 && nums[j] === nums[j - 1]) continue;
            let L = j + 1,
                R = len - 1;
            while (L < R) {
                const sum = nums[i] + nums[j] + nums[L] + nums[R];
                if (sum === target) {
                    newArr.push([nums[i], nums[j], nums[L], nums[R]]);
                    while (nums[L] === nums[L + 1]) L++;
                    while (nums[R] === nums[R - 1]) R--;
                    L++;
                    R--;
                }
                if (sum > target) R--;
                if (sum < target) L++;
            }
        }
    }
    return newArr;
};

 

  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
好的,下面是电话号码的字母组合问题的 C++ 代码实现: ``` class Solution { public: vector<string> letterCombinations(string digits) { unordered_map<char, string> mapping = { {'2', "abc"}, {'3', "def"}, {'4', "ghi"}, {'5', "jkl"}, {'6', "mno"}, {'7', "pqrs"}, {'8', "tuv"}, {'9', "wxyz"} }; vector<string> res; if (digits.empty()) { return res; } string combination; backtrack(res, combination, digits, 0, mapping); return res; } void backtrack(vector<string>& res, string& combination, string& digits, int index, unordered_map<char, string>& mapping) { if (index == digits.size()) { res.push_back(combination); return; } for (char c : mapping[digits[index]]) { combination.push_back(c); backtrack(res, combination, digits, index + 1, mapping); combination.pop_back(); } } }; ``` 其中 `letterCombinations` 函数用来生成所有的字母组合,`backtrack` 函数用来进行回溯操作。在 `letterCombinations` 函数中,首先根据数字字符和字母的映射关系创建了一个 `unordered_map` 对象 `mapping`。然后定义了一个空字符串 `combination` 和一个空 vector `res` 来保存最终结果。最后调用了 `backtrack` 函数来生成所有的字母组合。在 `backtrack` 函数中,首先判断是否达到了数字字符串的末尾,如果是,则将当前的 `combination` 字符串保存到 `res` 中。否则,遍历当前数字字符所能表示的所有字母,依次加入到 `combination` 字符串中,然后递归调用 `backtrack` 函数,添加下一个数字字符所能表示的字母。递归完成后,需要将 `combination` 字符串还原到上一个状态,以便进行下一次回溯。最终返回 `res` 数组即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值