链表算法题

单链表

 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 } } // 其他方法... }

 

猜你喜欢

转载自www.cnblogs.com/huahongcui/p/11520845.html