leetcode刷题记录(8)

1.环形链表

题目:

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

思路:先说最简单的,用map记录每个节点,然后依次比较即可

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function (head) {
  var map = new Map();
  while (head) {
    if (map.has(head)) return true;
    map.set(head, 111);
    head = head.next;
  }
  return false;
};

问题:没什么大问题,不过需要额外的空间,可以优化

优化方向:追及问题,又或者叫快慢指针。两个指针,一个跑得快一个跑得慢,如果有环形,那么肯定会相交的。

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function (head) {
    if (!head || !head.next) {
        return false
    }
    let fast = head
    let slow = head
    
    while (slow) {
        if (!fast || !fast.next) {
            return false
        }
        fast = fast.next.next
        slow = slow.next
        if (Object.is(fast, slow)) {
            return true
        }   
    }
    return false
};

2.最小栈

题目:

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。

思路:没啥说的,其实比较简单,这里就放基于数组的实现

var MinStack = function () {
  this.data = [];
};

/**
 * @param {number} x
 * @return {void}
 */
MinStack.prototype.push = function (x) {
  this.data.push(x);
};

/**
 * @return {void}
 */
MinStack.prototype.pop = function () {
  if (this.data.length) this.data.pop();
};

/**
 * @return {number}
 */
MinStack.prototype.top = function () {
  if (this.data.length) {
    return this.data[this.data.length - 1];
  } else {
    return null;
  }
};

/**
 * @return {number}
 */
MinStack.prototype.getMin = function () {
  if (this.data.length) {
    return Math.min(...this.data);
  } else {
    return null;
  }
};

基于链表也可以,大同小异

3.相交链表

题目:编写一个程序,找到两个单链表相交的起始节点。

注意:

如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。

思路:先还是说最简单的,用map来比较。先把第一个链表的节点存储,然后遍历第二个链表的节点。

/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
var getIntersectionNode = function(headA, headB) {
  let map = new Map();
  while (headA) {
    map.set(headA);
    headA = headA.next;
  }
  while (headB) {
    if (map.has(headB)) {
      return headB;
    }
    headB = headB.next;
  }
  return null;
};

问题:需要额外的空间

优化方向:双指针法。可以用两个指针同时跑,如果遍历一次之后交换,如果有相交,那么在第二次遍历的时候一定会在同一个节点结束

。如果不相交,那么第二次遍历时最后一个节点是null

/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
var getIntersectionNode = function(headA, headB) {
    let pa = headA;
    let pb = headB;
    while(pa !==pb){
        pa = pa? pa.next : headB;
        pb = pb? pb.next : headA;
    }
    return pa;
};

4.两数之和 II

题目:

给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。

函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。

说明:

返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。

思路:还是用之前的,不过可以优化的是,因为是有序数组,可以根据最大值和最小值优先排除一些元素,这样可以节省空间

/**
 * @param {number[]} numbers
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(numbers, target) {
  let l = numbers.length;
  let min = target - numbers[l - 1];
  let map = {};
  for (let i = 1; i <= l; i++) {
    if (numbers[i - 1] < min) continue;
    if (map[target - numbers[i - 1]]) return [map[target - numbers[i - 1]], i];
    map[numbers[i - 1]] = i;
  }
};

优化方向:对撞指针。两个指针一头一尾,相加,如果大于目标值,则尾部向前+1,如果小于目标值,则头部向前+1,直到得到结果

/**
 * @param {number[]} numbers
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(numbers, target) {
    let front=0;end=numbers.length-1;
    while(front<end){
        const frontNums=numbers[front];
        const endNums=numbers[end];
        if(frontNums+endNums>target){
           end--; 
        }
        if(frontNums+endNums<target){
            front++;
        }
        if(frontNums+endNums===target){
            // 答案是从1开始数,程序求出来起始点是0,所以 +1
            return [front+1,end+1]
        }
      
    }
};

5.Excell表列名称

题目:

给定一个正整数,返回它在 Excel 表中相对应的列名称。

例如,

    1 -> A
    2 -> B
    3 -> C
    ...
    26 -> Z
    27 -> AA
    28 -> AB 
    ...

示例 1:

输入: 1
输出: "A"

示例 2:

输入: 28
输出: "AB"

示例 3:

输入: 701
输出: "ZY"

思路:建立字母和数字的映射关系,A=>0,B=>1这样,然后循环操作数字,每次取26的余数作为当前,然后除以26的值作为下一轮的值

/**
 * @param {number} n
 * @return {string}
 */
let map=[ 'A', 'B', 'C', 'D', 'E', 'F', 'G',
    'H', 'I', 'J', 'K', 'L', 'M', 'N',
    'O', 'P', 'Q', 'R', 'S', 'T',
    'U', 'V', 'W', 'X', 'Y', 'Z']
var convertToTitle = function (n) {
    let result = ''
    while (n > 0) {
        n--
        result = map[(n%26)] + result;
        n = Math.floor(n / 26);
    }
    return result;

};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章