链表算法题

单链表

 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;
    }

 删除链表倒数第N个节点

//思路
这道题要用双指针来实现。先用fast指针前进n,然后让slow从head开始和fast一起前进,直到fast到了末尾,此时slow的下一个节点就是要删除的节点。
(另外,若fast一开始前进n就已经不在链表中了,说明要删除的节点正是head节点,那么直接返回head的下一个节点接口。)
/** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */ /** * @param {ListNode} head * @param {number} n * @return {ListNode} */ var removeNthFromEnd = function(head, n) { if(head===null){ return head } if(n===0){ return head; } let fast=head; let slow=head; while(n>0){ fast=fast.next; n--; } if(fast===null){ return head.next; } while(fast.next!=null){ fast=fast.next; slow=slow.next; } slow.next=slow.next.next; return head; };

 

单链表反转

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

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

//当基准节点的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
        }
    }

    // 其他方法...
}

 

posted @ 2019-09-15 00:01  siyecaohhc  阅读(300)  评论(0编辑  收藏  举报