链表算法题

Posted huahongcui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表算法题相关的知识,希望对你有一定的参考价值。

单链表

 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
        
    

    // 其他方法...

 

以上是关于链表算法题的主要内容,如果未能解决你的问题,请参考以下文章

Java集训(算法&&面试题)第四天 (链表 & 树)

链表算法题

数据结构与算法面试题80道

牛客网高频算法题系列-BM14-链表的奇偶重排

数据结构链表经典算法题集锦

大厂面试高频算法题,这10道题必须拿捏!