链表算法题

单链表

 function LinkedList() {
        //需要插入链表的元素
        var Node = function(element) {
            this.element = element;//元素的值
            this.next = null;//指向下一个节点项的指针
        };

        var length = 0;//链表的长度
        var head = null;//链表中第一个节点(的引用)

        //向链表尾部追加元素
        this.append = function(element) {

            var node = new Node(element), current;

            if(head === null) {
                //当链表为空时
                head = node;
            } else {
                //要从第一个元素找起
                current = head;

                //循环链表,直到找到最后一项
                while(current.next) {
                    current = current.next;
                }

                //把元素插入到链表的末尾
                current.next = node;
            }

            length++;
        };

        //从链表中根据位置移除元素并返回该元素
        this.removeAt = function(position) {
            if (position > -1 && position < length) {
                var current = head,
                    previous,
                    index = 0;

                //移除第一项
                if(position == 0) {
                    head = current.next;
                    return current.element;
                }else{
                    while(index++ < position){
                        previous = current;//删除指定位置前的一个元素
                        current = current.next;
                    }
                    previous.next = current.next;
                    length--;
                }
                return current.element;
            }else{
                return null;
            };
        }

        //从链表中根据值移除元素
        this.remove = function(element){
            var index = this.indexOf(element);
            return this.removeAt(index);
        };

        //在任意位置插入一个元素
        this.insert = function(position, element) {
            if(position > -1 && position <= length) {
                var node = new Node(element),
                    current = head,
                    previous,
                    index = 0;

                if(position === 0){ //在第一个位置添加
                    node.next = current;
                    head = node;
                }else{
                    while(index++ < position) {
                        previous = current;
                        current = current.next;
                    }
                    node.next = current;
                    previous.next = node;
                }
                length++;
                return true;
            }else{
                return false;
            }
        };

        //找到并返回一个元素的位置,如果元素不存在,返回-1
        this.indexOf = function(element) {
            var current = head,
                index = 0;

            while(current) {
                if(element === current.element) {
                    return index;
                }
                index++;
                current = current.next;
            }

            return -1;
        };

        //判断链表是否为空
        this.isEmpty = function() {
            return length === 0;
        };

        //返回链表的长度
        this.size = function() {
            return length;
        };

        //查看链表中元素的值(转换为字符串)
        this.toString = function() {
            var current = head,
                string = ‘‘;

            while(current) {
                string += "," + current.element;
                current = current.next;
            }
            return string.slice(1);
        };

        //返回链表中第一个元素
        this.getHead = function() {
            return head;
        };

        //查看链表(中的元素和指针,以数组形式输出)
        this.print = function() {
            var current = head,
                list = [];

            while(current) {
                list.push(current);
                current = current.next;
            }
            return list;
        };
    }

    var list = new LinkedList();
    list.append(5);
    console.log(list.toString());
    console.log(list.print());
    console.log(list.indexOf(115));
    console.log(list.isEmpty());
    console.log(list.size());
    console.log(list.getHead());

    console.log(list.removeAt(0));
    console.log(list.toString());
    console.log(list.removeAt(1));
    console.log(list.toString());

    list.insert(0, 500);
    console.log(list.toString());

删除链表中重复的结点

//思路

特殊情况:单链表,空链表
新建一个节点newHead,放在头节点前面,当头节点需要被删除时,方便返回结果
pre指针指向前一个节点(初始为newHead)cur指向当前节点(初始为头节点),next指向下一个节点(初始为null)
cur不空,cur.next不空时,进入循环,依次比较节点,next保存cur.next
如果cur和next值相等,就进入循环,依次向后查找所有重复元素,然后删除中间所有重复元素(pre.next = next;),cur指向next的当前位置
如果cur和next值不相等,pre和cur依次向后移动,继续比较
最后遍历结束,退出循环,返回头节点:newHead.next

function deleteDuplication(pHead) {
  if (!pHead || !pHead.next) return pHead;
  let newHead = new ListNode("head"); //新建一个节点
  newHead.next = pHead; //充当新的头节点,当head节点被删除时可以返回正确的头节点
  let pre = newHead; //pre指向前一个节点
  let cur = pHead; //cur指向当前节点
  let next = null; //next指向下一个节点
  while (cur && cur.next) {
    //当前节点不空且下一个节点不空时,进入比较循环
    next = cur.next; //next存放下个节点的位置
    if (next.val === cur.val) {
      //cur和next值相等
      //进入循环向后查找所有重复元素
      while (next && next.val === cur.val) {
        next = next.next; //next后移一位
      }
      //next空或者next和cur值不相等,退出循环
      pre.next = next; //删除中间重复的节点
      cur = next; //cur指针指向next的位置
    } else {
      //cur和next值不相等
      pre = cur; //pre和cur都后移
      cur = next;
    }
  }
  return newHead.next;
}

回文链表

var isPalindrome = function(head, queue = []) {
  if (!head) {
    return true;
  }
  queue.push(head.val);
  let flag = isPalindrome(head.next, queue);
  return queue.shift() === head.val && flag;
}

查找单链表中间节点

<!--查找单链表的中间结点:
定义两个节点k1、k2,k1一次走两步,k2一次走一步,
当k2走到尽头时此时k1所在的位置中间节点。-->

<!--输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。

-->

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

    var middleNode = function(head) {
        var length = 1,
            node = head;
        //测量链表长度
        while(node.next !== null){
            length++;
            node = node.next;
        }
        //设置中间长度
        if(length % 2 === 0){
            length = length / 2 + 1;
        }else{
            length = Math.ceil(length / 2);
        }
        //重新查找中间长度的节点
        node = head;
        while(length !== 1){
            node = node.next;
            length--;
        }

        return node;
    };

查找单链表倒数第K个节点

//思路
简单思路: 循环到链表末尾找到 length 在找到length-k节点 需要循环两次。

//优化:

设定两个节点,间距相差k个节点,当前面的节点到达终点,取后面的节点。

前面的节点到达k后,后面的节点才出发。

//代码鲁棒性: 需要考虑head为null,k为0,k大于链表长度的情况。

function FindKthToTail(head, k) {
      if (!head || !k) return null;
      let front = head;
      let behind = head;
      let index = 1;
      while (front.next) {
        index++;
        front = front.next;
        if (index > k) {
          behind = behind.next;
        }
      }
      return (k <= index) && behind;
    }

单链表反转

//以链表的头部节点为基准节点

//将基准节点的下一个节点挪到头部作为头节点

//当基准节点的next为null,则其已经成为最后一个节点,链表已经反转完成

 var reverseList = function (head) {
      let currentNode = null;
      let headNode = head;
      while (head && head.next) {
        currentNode = head.next;
        head.next = currentNode.next;
        currentNode.next = headNode;
        headNode = currentNode;
      }
      return headNode;
    };

数组转链表

function array2list(ary) {
    if(!ary.length) {
        return null
    }

    var node
    var head = {value: ary[0], next: null}
    var pnode = head  //pnode变量用来保存前一个节点

    for(var i = 1; i < ary.length; i++) {
        node = {value: ary[i], next:null}
        pnode.next = node   //将前一个节点的next指向当前节点
        pnode = node   //将node赋值给pnode
    }

    return head
}

链表转数组

function list2array(head) {
    if(!head) {
        return []
    }
    var result = [head.value]
    var restValues = list2array(head.next)
    return result.concat(restValues)
}

奇偶链表

//题目:给定单链表,将所有奇数节点组合在一起,然后是偶数节点。
//思路

特殊情况,空/单/双链表不需要修改顺序
odd指向奇数节点,even指向偶数节点,evenHead保存第一个偶节点
while循环控制后移,条件:even && odd && even.next,因为even.next需要even存在,所以要先判断even,因为odd.next夹在了中间,所以只需要判断最后的额 even.next存在
odd在even前,所以先移动odd——先改变.next指针,再将odd/even指向.next的位置。
最后连接奇偶链表,返回头节点head

var oddEvenList = function(head) {
  if (!head || !head.next || !head.next.next) {
    return head;
  }
  let odd = head, //odd指向奇数节点
    evenHead= head.next,
    even = head.next; //even指向偶数节点,evenHead保存第一个偶节点
  while (even && odd && even.next) {
    odd.next = even.next; //奇节点指向奇节点
    odd = odd.next; //odd指针移向下一个奇节点
    even.next = odd.next; //偶节点指向偶节点
    even = even.next; //even指针移向下一个奇节点
  }
  odd.next = evenHead; //连接奇偶链表
  return head;
}; 

合并两个单链表

//思路:

对两个链表,各自设置一个游标节点指向头节点,对游标节点上的数值进行比较,

小节点的next等于小节点的next和大节点的较小值。数值小的那个拿出来放入到合并链表中,

如此递归。

返回小节点。

//考虑代码的鲁棒性,也是递归的终止条件,两个head为null的情况,取对方节点返回。
function Merge(pHead1, pHead2) {
      if (!pHead1) {
        return pHead2;
      }
      if (!pHead2) {
        return pHead1;
      }
      let head;
      if (pHead1.val < pHead2.val) {
        head = pHead1;
        head.next = Merge(pHead1.next, pHead2);
      } else {
        head = pHead2;
        head.next = Merge(pHead1, pHead2.next);
      }
      return head;
    }

两个链表的第一个公共节点

//思路
1.先找到两个链表的长度length1、length2

2.让长一点的链表先走length2-length1步,让长链表和短链表起点相同

3.两个链表一起前进,比较获得第一个相等的节点

时间复杂度O(length1+length2) 空间复杂度O(0)

function FindFirstCommonNode(pHead1, pHead2) {
      if (!pHead1 || !pHead2) { return null; }
      // 获取链表长度
      let length1 = getLength(pHead1);
      let length2 = getLength(pHead2);
      // 长链表先行
      let lang, short, interval;
      if (length1 > length2) {
        lang = pHead1;
        short = pHead2;
        interval = length1 - length2;
      } else {
        lang = pHead2;
        short = pHead1;
        interval = length2 - length1;
      }
      while (interval--) {
        lang = lang.next;
      }
      // 找相同节点
      while (lang) {
        if (lang === short) {
          return lang;
        }
        lang = lang.next;
        short = short.next;
      }
      return null;
    }

    function getLength(head) {
      let current = head;
      let result = 0;
      while (current) {
        result++;
        current = current.next;
      }
      return result;
    }

双向链表

// 链表节点
class Node {
    constructor(element) {
        this.element = element
        this.prev = null
        this.next = null
    }
}

// 双向链表
class DoublyLinkedList {

    constructor() {
        this.head = null
        this.tail = null
        this.length = 0
    }

    // 任意位置插入元素
    insert(position, element) {
        if (position >= 0 && position <= this.length){
            const node = new Node(element)
            let current = this.head
            let previous = null
            let index = 0
            // 首位
            if (position === 0) {
                if (!head){
                    this.head = node
                    this.tail = node
                } else {
                    node.next = current
                    this.head = node
                    current.prev = node
                }
            // 末位
            } else if (position === this.length) {
                current = this.tail
                current.next = node
                node.prev = current
                this.tail = node
            // 中位
            } else {
                while (index++ < position) {
                    previous = current
                    current = current.next
                }
                node.next = current
                previous.next = node
                current.prev = node
                node.prev = previous
            }
            this.length++
            return true
        }
        return false
    }

    // 移除指定位置元素
    removeAt(position) {
        if (position > -1 && position < this.length) {
            let current = this.head
            let previous = null
            let index = 0

            // 首位
            if (position === 0) {
                this.head = this.head.next
                this.head.prev = null
                if (this.length === 1) {
                    this.tail = null
                }

            // 末位
            } else if (position === this.length - 1) {
                this.tail = this.tail.prev
                this.tail.next = null

            // 中位
            } else {
                while (index++ < position) {
                     previous = current
                     current = current.next
                }
                previous.next = current.next
                current.next.prev = previous
         }
         this.length--
         return current.element
        } else {
            return null
        }
    }

    // 其他方法...
}

原文地址:https://www.cnblogs.com/huahongcui/p/11520845.html

时间: 2024-10-18 07:25:53

链表算法题的相关文章

反转链表算法题

反转一个单链表. 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 进阶:你可以迭代或递归地反转链表.你能否用两种方法解决这道题? 解决方案 方法一:迭代 假设存在链表 1 → 2 → 3 → Ø,我们想要把它改成 Ø ← 1 ← 2 ← 3. 在遍历列表时,将当前节点的 next 指针改为指向前一个元素.由于节点没有引用其上一个节点,因此必须事先存储其前一个元素.在更改引用之前,还需要另一个

leetcode链表算法题实现思路

找出两个链表的交点(leetcode160) 一条链表遍历完之后跳转到下一条链表的头节点继续遍历.  因为当两条链表均被遍历一遍以后,第二次遍历时会同时到达节点相等的地方.如果没有相交的节点,两条链表均遍历两遍后,同时等于null,故返回null. public ListNode getIntersectionNode(ListNode headA, ListNode headB) { ListNode l1 = headA, l2 = headB; while (l1 != l2) { l1

算法题——翻转链表中的一段

题目:给出一个链表中的两个指针p1和p2,将其之间的结点翻转. 思路:可以通过交换结点内的值来实现结点的翻转,空间为O(N):如果要求不能交换值,那么仅凭p1和p2是无法翻转的,只能交换两个指针之间的链表. 代码: 交换值: 1 struct ListNode 2 { 3 int val; 4 ListNode *next; 5 }; 6 7 void reverseNodes(ListNode *p1, ListNode *p2) { 8 if ( p1 == NULL || p2 == NU

算法题:复制复杂链表之空间换时间法

说明:本文仅供学习交流,转载请标明出处,欢迎转载!  题目:复制一个复杂链表,所谓复杂链表指的是每个节点含有两个指针,一个指向单链表的下一个结点,一个指向单链表中的任意某个结点,或者该指针为空. 为了方便起见,我们将待复制的链表称为原型链表,将复制后的新链表称为复制链表,将指向下一个结点的指针定义为next指针,指向其他位置的指针定义为any指针.<剑指offer>上给出了三种解决方法:(1)常规法:(2)空间换时间法:(3)紧随复制法.书上并给出了第三种方法的实现代码.这里我根据书上的提示,

算法题:复制复杂链表之复制连接法

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 上篇文章算法题:复制复杂链表之空间换时间法我们给出了用映射的方法来为新复制的链表中的每个结点设置any指针,本文给出的是<剑指offer>上给出的算法与代码,<剑指offer>上提到该算法的实现三个步骤:        第一步:复制原始链表的任意结点N并创建新结点N',在把N'连接到N的后面:        第二步:设置每个结点的any指针:        第三步:将长链表分成两个链表,一个是原始链表,另外一个就是我们所要求的复制

算法题——二叉树转换为左单链表

题目:给定一棵二叉树,将所有的结点都放到左儿子的位置,即除了root结点外,每一个结点都是其他某一个结点的左儿子.不用保持某种顺序,不能递归,O(1)空间. 思路: 我的想法是,维持一个遍历指针p,另一个指针tail永远指向向左遍历到底的结点: 初始化p和tail都为root,开始循环: 如果p为叶子结点,则退出循环: 如果p没有右儿子,则向左下降一层: 如果p有右儿子,则tail向左遍历到底,将p的右子树挂到tail的左儿子上,p右儿子赋空值,然后向左下降一层. p每次下降一层时,tail从上

经典算法题每日演练——第二十一题 十字链表

原文:经典算法题每日演练--第二十一题 十字链表 上一篇我们看了矩阵的顺序存储,这篇我们再看看一种链式存储方法“十字链表”,当然目的都是一样,压缩空间. 一:概念 既然要用链表节点来模拟矩阵中的非零元素,肯定需要如下5个元素(row,col,val,down,right),其中: row:矩阵中的行. col:矩阵中的列. val:矩阵中的值. right:指向右侧的一个非零元素. down:指向下侧的一个非零元素. 现在我们知道单个节点该如何表示了,那么矩阵中同行的非零元素的表示不就是一个单链

经典算法题每日演练——第二十五题 块状链表

原文:经典算法题每日演练--第二十五题 块状链表 在数据结构的世界里,我们会认识各种各样的数据结构,每一种数据结构都能解决相应领域的问题,每一种数据结构都像 是降龙十八掌中的某一掌,掌掌毙命... 当然每个数据结构,有他的优点,必然就有它的缺点,那么如何创造一种数据结构 来将某两种数据结构进行扬长避短,那就非常完美了.这样的数据结构也有很多,比如:双端队列,还有就是今天讲的 块状链表, 我们都知道 数组 具有 O(1)的查询时间,O(N)的删除,O(N)的插入... 链表 具有 O(N)的查询时

算法题:反转单链表

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 题目:存在一个单链表,头指针为head,实现单链表的反转Node *Reverse(Node *head).  该算法的求解办法有很多,如: 方法1:先顺序变量单链表,将结点保存到栈中,在从栈中弹出结点,重新建立一个新的单链表: 方法2:用<剑指offer>里面给出的算法,用三个指针来实现: 方法3:采用递归实现,是方法2的递归实现形式. 本文主要给出方法2和方法3,在给出具体的代码之前,先要注意几个问题:          (1)如果hea