[路飞]_力扣算法题练习二:反转链表、链表相交、旋转链表、数据流中的第 K 大元素、翻转二叉树

196 阅读3分钟

反转链表

力扣链接

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:

rev1ex1.jpg

输入: head = [1,2,3,4,5]
输出: [5,4,3,2,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
 * @return {ListNode}
 */
var reverseList = function(head) {
    var pre = null
    var curr = head
    while (head) {
        curr = head;
        head = head.next
        curr.next = pre
        pre = curr
    }
    return curr
};
  • 递归法
/**
 * 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) { 
    if (!head || !head.next) return head 
    var newHead = reverseList(head.next) 
    var next = head.next head.next.next = head 
    head.next = null 
    return newHead 
};

链表相交

力扣链接

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:

inorder_1.jpg

  • 双指针
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
var getIntersectionNode = function(headA, headB) {
   var A = headA;
   var B = headB;
   while(A !== B){
       A = A === null ? headB : A.next;
       B = B === null ? headA : B.next;
   }
   return A
};

  • 双循环
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
var getIntersectionNode = function(headA, headB) {
    var cloneA = headA
    var cloneB = headB
    while(cloneA){
        while(cloneB){
            if(cloneA === cloneB){
                return cloneB
            }
            cloneB = cloneB.next
        }
        cloneA = cloneA.next
        cloneB = headB
    }
    return null
};
  • 利用高阶函数
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
var getIntersectionNode = function(headA, headB) {
    var lastA = headA
    var lastB = headB
    var valArr = []
    while(lastA){
        valArr.push(lastA)
        lastA = lastA.next
    }
    while(lastB){
        if(valArr.includes(lastB)) return lastB
        lastB = lastB.next
    }
    return null
};

旋转链表

力扣链接

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

rotate1.jpg

输入: head = [1,2,3,4,5], k = 2
输出: [4,5,1,2,3]
  • 利用数组
/**
 * 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} k
 * @return {ListNode}
 */
var rotateRight = function(head, k) {
    var arr = []
    var cloneHead = head
    while (cloneHead) {
        arr.push(cloneHead)
        cloneHead = cloneHead.next
    }
    var len = arr.length
    if (k > len) {
        k = k % len
    }
    if (!head || k === 0 || len === 1 || len === k) {
        return head
    }
   
    var newHead = arr[len - k]
    arr[len - k - 1].next = null
    arr[len - 1].next = arr[0]
    return newHead
};

  • 闭合为环
/**
 * 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} k
 * @return {ListNode}
 */
var rotateRight = function(head, k) {
    if (k === 0 || !head || !head.next) {
        return head;
    }
    let n = 1;
    let cur = head;
    while (cur.next) {
        cur = cur.next;
        n++;
    }

    let add = n - k % n;
    if (add === n) {
        return head;
    }

    cur.next = head;
    while (add) {
        cur = cur.next;
        add--;
    }

    const ret = cur.next;
    cur.next = null;
    return ret;
};

数据流中的第 K 大元素

力扣链接

设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。

请实现 KthLargest 类:

KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。 int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。

输入:
["KthLargest", "add", "add", "add", "add", "add"]
[[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]]
输出:
[null, 4, 5, 5, 8, 8]

解释:
KthLargest kthLargest = new KthLargest(3, [4, 5, 8, 2]);
kthLargest.add(3);   // return 4
kthLargest.add(5);   // return 5
kthLargest.add(10);  // return 5
kthLargest.add(9);   // return 8
kthLargest.add(4);   // return 8
  • 按顺序放入数组中,直接拿出第K大的值
/**
 * @param {numberk
 * @param {number[]nums
 */
var KthLargest = function(k, nums) {
    this.k = k
    this.valArr = nums.sort((a, b) => b - a) || []
};
/** 
 * @param {numberval
 * @return {number}
 */
KthLargest.prototype.add = function(val) {
    var len = this.valArr.length
    if (len === 0) {
        this.valArr.push(val)
        return this.valArr[this.k - 1]
    }
    if (val >= this.valArr[0]) {
        this.valArr.unshift(val)
        return this.valArr[this.k - 1]
    }
    if (val <= this.valArr[len - 1]) {
        this.valArr.push(val)
        return this.valArr[this.k - 1]
    }
    if (len === 2) {
        this.valArr.splice(10, val)
        return this.valArr[this.k - 1]
    }
    var start = 0;
    var end = len - 1;
    var flag = true;
    while (flag) {
        var middle = (end + start) >> 1
        var pre = this.valArr[middle - 1]
        var next = this.valArr[middle + 1]
        if (this.valArr[middle] >= val) {
            if (val >= next) {
                this.valArr.splice(middle + 10, val)
                flag = false
                break
            }
        }
        if (val >= this.valArr[middle]) {
            if (pre >= val) {
                this.valArr.splice(middle, 0, val)
                flag = false
                break
            }
        }
        if (this.valArr[middle] < val) {
            end = middle
        }
        if (this.valArr[middle] > val) {
            start = middle
        }
    }
    return this.valArr[this.k - 1]
};

翻转二叉树

力扣链接

翻转一棵二叉树。

输入:

     4
   /   \
  2     7
 / \   / \
1   3 6   9

输出:

     4
   /   \
  7     2
 / \   / \
9   6 3   1
  • 递归法
/**
 * @param {TreeNoderoot
 * @return {TreeNode}
 */
var invertTree = function(root) {
    if(!root) return root
    let temp = root.left
    root.left = root.right
    root.right = temp
    invertTree(root.left)
    invertTree(root.right)
    return root
};
  • 深度优先遍历
var invertTree = function(root) {
    if(!root) return root
    var stack = []
    stack.push(root)
    while(stack.length>0){
        var node = stack.pop();
        var temp = node.left
        node.left = node.right
        node.right = temp
        if(node.right) stack.push(node.right)
        if(node.left) stack.push(node.left)
    }
    return root
};
  • 层序遍历
var invertTree = function(root) {
   if(!root) return root
    var queue = []
    queue.push(root)
    while(queue.length>0){
        var node = queue.shift();
        var temp = node.left
        node.left = node.right
        node.right = temp
        if(node.right) queue.push(node.right)
        if(node.left) queue.push(node.left)
    }
    return root
};