算法数据结构和算法分析二叉树之下

2019 算法面试相关(leetcode)--数组和链表

2019-01-08  本文已影响2人  Theendisthebegi

链表和数组作为算法中的两个基本数据结构,在程序设计过程中经常用到。尽管两种结构都可以用来存储一系列的数据,但又各有各的特点。
数组的优劣势:可以方便的遍历查找需要的数据,时间复杂度为O(1)。这种时间上的便利性,是因为数组在内存中占用了连续的空间,在进行类似的查找或者遍历时,本质是指针在内存中的定向偏移。然而,当需要对数组成员进行添加和删除的操作时,数组内完成这类操作的时间复杂度则变成了O(n)
链表的优劣势:在某些操作上比数组更加高效,例如当进行插入和删除操作时,链表操作的时间复杂度仅为O(1)。因为链表在内存中不是连续存储的,所以可以充分利用内存中的碎片空间。
提到数组就不得不提到数组的排序:七种常见的数组排序算法整理(C语言版本)

function ListNode(val) {
    this.val = val;
    this.next = null;
}

一、3种方法实现反转链表

var reverseList = function(head) {
   
    if (!head || !head.next) return head;
    
    let newHead = reverseList(head.next);
    
    head.next.next = head;
    
    head.next = null;
    
    return newHead;
};
var reverseList = function(head) {

    if (!head || !head.next) return head;

    let lastNode = new ListNode(head.val), curNode;

    let node = head.next;

    while (node) {

        curNode = new ListNode(node.val);

        curNode.next = lastNode;

        lastNode = curNode;

        node = node.next;
    }

    return curNode;
};
var reverseList = function(head) {
    
    if(!head || !head.next) return head

    let pre = head, cur, last = head.next;

    head.next = null;

    while (last) {

        cur = last;

        last = cur.next;

        cur.next = pre;

        pre = cur;
    }

    return cur;
};

二 、两两交换链表中的节点
记录相邻两个结点cur和last,以及之前的结点prev,然后去进行反转相邻的两个结点,依次循环到最后

var swapPairs = function(head) {
    
    if(!head || !head.next) return head
    
    let res = head.next

    let cur = head

    let prev = last = null

    while(cur && cur.next){

        last = cur.next

        cur.next = last.next

        last.next = cur

        if(prev) prev.next = last

        prev = cur

        cur = cur.next
    }

    return res
};

三、环形链表
正常链表都是有头有尾的,而环形链表则是没有尾的,它的尾会指向其中一个结点(不一定是指向头结点),也就是环形链表,该题目就是来判断一个链表是否是环形链表。
正常来说,对链表进行循环,如果存在尾指针,即某结点指向null,即可证明该链表不是环形链表。但如果对环形链表进行循环的话,会造成死循环,这样就没办法确定是链表足够长还是该链表是环形链表。

var hasCycle = function(head) {
    
    let nodes = []

    while(head){

        if(nodes.indexOf(head)) return true

        nodes.push(head)

        head = head.next
    }

    return false
};
//这里使用快慢指针,slow每次走一步,fast每次走两步,如果不是环形链表,则会一直循环下去,永远不会相遇,直至循环结束。
//反之如果这两个指针相遇,则说明该链表是环形链表。
var hasCycle = function(head) {
    
    let slow = fast = head

    while(fast && fast.next){

        slow = slow.next

        fast = fast.next.next

        if(slow == fast) return true
    }

    return false
};

四、 环形链表 II
题目意思是如果链表是环形链表,就返回交点(链表尾连接到链表中的位置)在该链表中的位置,否则返回null
如果是用方法1使用数组保存结点,很容易就可以做到,这里不再赘述
快慢指针的话,首先先循环一次,判断是否是环形链表,不是的话直接返回null。是的话,则记录下相遇点。然后head开始跑,同时fast指针继续从相遇点跑,则head必然会和fast指针在环形链表交点相遇。

var detectCycle = function(head) {
    
    let slow = fast = head

    while(fast && fast.next){

        slow = slow.next

        fast = fast.next.next

        if(slow == fast) {
        
            while(fast != head){
        
                head = head.next
        
                fast = fast.next
            }

            return head
        }
    }

    return null
};
上一篇下一篇

猜你喜欢

热点阅读