首页 > 其他分享 >两两交换节点位置:递归法、迭代法和数组转换法

两两交换节点位置:递归法、迭代法和数组转换法

时间:2023-04-06 16:14:04浏览次数:40  
标签:head 转换法 递归 nextNode next 当前 return 迭代法 节点

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>两两交换节点位置</title>
</head>

<body>
    <script>
        class ANode {
            constructor(value) {
                this.value = value;
                this.next = null;
            }
        }

        // 从一个数组,创建一个nodeList并返回它的head
        function createNodeList(nodeList) {
            if(!nodeList || nodeList.length===0) return null;

            const head = new ANode(nodeList[0]);
            let cur = head;
            for(let i=0; i<nodeList.length-1; i++) {
                cur.next = new ANode(nodeList[i+1]);
                cur = cur.next;
            }
            return head;
        }

        // 打印nodeList, eg: nodeList: (1) => (2) => (3) => (4) => null
        function printNodeList(head, nodeListName = "nodeList") {
            let str = `(${head.value}) => `;
            while(head && head.next!==null) {
                head = head.next;
                str += `(${head.value}) => `;
            }
            str += "null";
            console.log(`${nodeListName}: ${str}`);
        }

        /**
         * @address: https://juejin.cn/post/7218584877910212667
         * @description: 递归回溯方法   TC:O(n)  SC:O(n)
         * @author: JunLiangWang
         * @param {*} node
         * @return {*}
         */
        function recursionBacktracking(node) {
            /**
             * 该方案利用递归回溯的方式,递归判断当前节点以及其后一个节点是否存在,
             * 如果不存在,证明已无节点可交换,则直接返回当前节点;否则,则将当前
             * 节点与其下一个节点进行交换。交换过程为:先将当前节点的下一个节点取
             * 出并保存(nextNode),然后将当前节点的下一个节点更新为nextNode后续
             * 节点继续递归的结果,然后将nextNode的下一个节点更新为当前节点,此时
             * nextNode则变更为当前节点的前一个节点,返回nextNode即可。
             */

            // 判断当前节点与其下一个节点是否存在,如果存在则将两节点位置交换
            if (node && node.next) {
                // 先保存当前节点的下一个节点(nextNode)
                let nextNode = node.next;
                // 将当前节点的下一个节点更新为nextNode后续节点继续递归的结果
                node.next = recursionBacktracking(nextNode.next);
                // 将nextNode的下一个节点更新为当前节点
                nextNode.next = node;
                // 此时nextNode已为当前节点的前一个节点,返回nextNode即可
                return nextNode;
            }
            // 不存在证明已无可交换节点,直接返回即可当前节点即可
            else {
                return node;
            }
        }

        /**
         * @address: https://juejin.cn/post/7218584877910212667
         * @description: 迭代法    TC:O(n)   SC:O(n)
         * @author: JunLiangWang
         * @param {*} head
         * @return {*}
         */
        function iteration(head) {
            /**
             * 该方案利用迭代,每次遍历链表的两个节点,将其交换,直至遍历结束
             */
            // 如果当前节点为空或其后一个节点为空,证明无需要交换的节点,直接返回当前节点即可
            if (!head || !head.next) return head;
            // 新的头节点为原链表的第二个节点
            const NEW_HEAD = head.next;
            // 上一个节点初值为空
            let lastNode = null;
            // 当前节点初值为原链表第一个节点
            let currentNode = head;
            // 当前节点不为空且其下一个节点也不为空,证明仍存在需要交换的节点
            while (currentNode && currentNode.next) {
                // 将当前节点的下一个节点取出保存(nextNode)
                let nextNode = currentNode.next;
                // 将当前节点的下一个节点更新为nextNode的下一个节点
                currentNode.next = nextNode.next;
                // nextNode的下一个节点更新为当前节点,此时位置已完成交换
                nextNode.next = currentNode;
                // 如果存在上一个节点,则需要将上一个节点的下一个节点更新为
                // 已经交换位置的nextNode
                if (lastNode) lastNode.next = nextNode;
                // 上一个节点更新为当前节点
                lastNode = currentNode;
                // 当前节点更新为其下一个节点
                currentNode = currentNode.next;
            }
            // 返回新链表
            return NEW_HEAD;
        }

        // 单向链表转换成数组
        function nodeListToArray(head) {
            if(!head) return [];

            const res = [head];
            while(head && head.next!==null) {
                head = head.next;
                res.push(head);
            }
            return res;
        }

        // 数组转换法
        function byArray(head) {
            const transformedArr = nodeListToArray(head);
            if(!transformedArr || transformedArr.length===0) return null;
            for(let i=0; i<transformedArr.length; i++) {
                let pre = transformedArr[i];
                let next = transformedArr[i+1];
                // 元素个数为奇数时,最后一个不交换
                if(next) {
                    [pre, next] = [next, pre];
                }
            }
            return createNodeList(transformedArr[0]);
        }

        const nodeList1 = createNodeList([1, 2, 3, 4]);
        const nodeList2 = createNodeList([1, 2, 3, 4]);
        const nodeList3 = createNodeList([1, 2, 3, 4]);
        printNodeList(nodeList1, "nodeList1");
        printNodeList(nodeList2, "nodeList2");
        printNodeList(nodeList3, "nodeList2");

        // 递归法
        const newHead1 = recursionBacktracking(nodeList1);
        printNodeList(newHead1, "递归法");

        // 迭代法
        const newHead2 = iteration(nodeList2);
        printNodeList(newHead2, "迭代法");

        // 数组转换法
        const newHead3 = byArray(nodeList3);
        printNodeList(newHead2, "数组转换法");
    </script>
</body>

</html>

image

标签:head,转换法,递归,nextNode,next,当前,return,迭代法,节点
From: https://www.cnblogs.com/pangqianjin/p/17293082.html

相关文章

  • 函数的递归
    递归:程序调用自身的编程技巧叫递归。最简单的递归:#include<stdio.h>intmain(){ printf("haha\n"); main(); return0;}注意:会栈溢出。栈区:储存局部变量、函数形参。堆区:储存动态开辟的内存,比如:malloc、calloc。静态区:储存全局变量、static修饰的变量。两个必要条件:1,存在限......
  • 递归与回溯_正则问题()|x
    acwing1225正则问题(递归回溯)考虑一种简单的正则表达式:只由x()|组成的正则表达式。小明想求出这个正则表达式能接受的最长字符串的长度。例如((xx|xxx)x|(x|xx))xx能接受的最长字符串是:xxxxxx,长度是6。思路:遇到'(''|'就进行递归,遇到')'就进行回溯,每次递归dfs(......
  • js 递归遍历树形结构数据,返回新的数组
    工作中,我们经常会遇到这样的情况:后端返回的数组,只需要取name、value生成新的数组,或者是将某个属性名修改,生成新的数组。递归是一种常见的解决问题的方法,即把问题逐渐简单化。“递归”的基本思想是:自己调用自己。实例如下handleDg(arrs,that){arrs.map((item,index)......
  • 【递归 WITH】递归查询树结构数据
    递归语句WITHtempTable(ID)AS(SELECTIDFROMsys_menuWHEREID='05161001'ANDDEL_STATUS=1UNIONALLSELECTm.IDFROMsys_menumJOINtempTableONm.PARENT_ID=tempTable.IDANDDEL_STATUS=1)SELECT*FROMtempTable;比如菜单树,拿到某个菜单,要查询它下......
  • 二叉树的统一迭代法
    classTreeNode{public:intval;TreeNode*left;TreeNode*right;TreeNode():val(NULL),left(nullptr),right(nullptr){}TreeNode(intx):val(x),left(nullptr),right(nullptr){}};classSolution{public:vector<int>inorderTrav......
  • 二叉树的前中后序遍历(非递归)
    classTreeNode{public:intval;TreeNode*left;TreeNode*right;TreeNode():val(NULL),left(nullptr),right(nullptr){}TreeNode(intx):val(x),left(nullptr),right(nullptr){}};classSolution{public:vector<int>preorderTra......
  • 递归算法
    递归算法 递归算法是一种通过调用自身来解决问题的算法。递归算法通常涉及到将一个问题划分为较小的子问题来解决,并在子问题中调用自身来完成。递归算法的基本思想是,将一个大问题转化为一个或多个相同结构的小问题,直到问题变得足够小以便直接解决。然后将这些小问题的解组合成......
  • 递归实现排列型枚举
    #include<iostream>usingnamespacestd;constintN=10;intn;intstate[N];boolused[N];voiddfs(intu){if(u==n+1){for(inti=1;i<=n;i++){cout<<state[i]<<"";}cout<<end......
  • 递归相关题
    遵循四个原则,1)程序执行一个函数时,就创建一个新的受保护的独立空间(新函数栈)2)函数的局部变量是独立的,不会相互影响3)递归必须向退出递归的条件逼近,否则就是无限递归,死龟了:)4)当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁。斐波那契数列请使......
  • 两两交换链表中的节点|递归
    两两交换链表中的节点链表中每两两相邻的节点将其对调位置,涉及的主要操作位交换节。但需要注意初始位置的交换即返回值,以及奇数个节点的处理方法,这里给出两种方法,迭代和......