算法:排序-数组-链表

200 阅读7分钟

排序

时间复杂度

冒泡排序动画

冒泡排序

  for (let i = 1; i < arr.length; i++) {
    let flag = true;
    for (let j = 0; j < arr.length - i; j++) {
      if (arr[j] > arr[j + 1]) {
        const temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
        flag = false;
      }
    }
    if (flag) {
      return arr;
    }
  }
  return arr;
}

选择排序

  for (let i = 1; i < arr.length; i++) {
    let j = i;
    const temp = arr[i];
    while(j > 0 && temp > arr[j - 1]) {
      arr[j] = arr[j - 1]; 
      j--;
      
    }
    if (j !== i) {
      arr.splice(j, 1, temp);
    }
  }
  return arr;
}

希尔排序

function shellSort(arr) {
  let gap = 1;
  while(gap < arr.length) {
    gap = gap * 3 + 1;
  }
  while(gap > 0) {
    for (let i = gap; i < arr.length; i++) {
      let temp = arr[i];
      let j = i - gap;
      
      while (j >= 0 && arr[j] > temp) {
         arr[j + gap] = arr[j];
         j -= gap;
      }
      arr[j + gap] = temp;
    }
    gap = Math.floor(gap/3);
  }
  return arr;
}

快速排序


function quickSort(arr) {
  sort(arr, 0, arr.length - 1);
}
function sort(arr, l, r) {
  if (l < r) {
    let index = partion(arr, l, r);
    sort(arr, l , index - 1);
    sort(arr, index + 1, r);
  }
}
function partion(arr, l, r) {
  let temp = arr[l], i = l, j = r;
  while(i < j) {
    while(arr[j] > temp && i < j) {
      j --;
    }
    while(arr[i] < temp && i < j) {
      i ++;
    }
    swap(arr, i, j);
  }
  swap(arr, i, j);
  return i;
  
}
function swap(arr, i, j) {
    let k = arr[i];
    arr[i] = arr[j];
    arr[j] = k;
}

数组

盛水最多的容器 11题

双指针

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    let i = 0, j = height.length - 1;
    let res = -1;
    while(i < j) {
        if (height[i] < height[j]) {
            res = Math.max(res, height[i] * (j - i));
            i++;
        } else {
            res = Math.max(res, height[j] * (j - i));
            j --;
        }
    }
    return res;
};

除自身以外数组的乘积 题238

给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。 示例: 输入: [1,2,3,4] 输出: [24,12,8,6]

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var productExceptSelf = function(nums) {
    let res = [];
    let p = 1, q = 1;
    for (let i = 0; i < nums.length; i++) {
        res[i] = p;
        p *= nums[i];
    }
    for (let i = nums.length - 1; i > 0 ; i--) {
        q *= nums[i];
        res[i - 1] *= q;
    }
    return res;
};

三数之和 题15

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例:

给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    let res = [];
    nums.sort((a, b) => a - b);
    for (let i = 0; i < nums.length; i++) {
        let n1 = nums[i];
        if (n1 > 0) break;
        if (nums[i - 1] === n1 && i > 0) continue;
        let left = i + 1;
        let right = nums.length - 1;
        while(left < right) {
            let n2 = nums[left];
            let n3 = nums[right];
            if (n1 + n2 + n3 === 0) {
                res.push([n1, n2, n3]);
                while (nums[left] === n2) left++;
                while (nums[right] === n3) right --;
            } else if (n1 + n2 + n3 < 0) {
                left ++;
            } else {
                right --;
            }
        }
    }
    return res;
};

链表

反转链表[题206](leetcode-cn.com/problems/re…

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    let pre = null;
    let cur = head;
    let tmp = null;
    while(cur !== null) {
        tmp = cur.next;
        cur.next = pre;
        pre = cur;
        cur = tmp;
    }
    return pre;
};

合并两个有序链表 题21

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例:

输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var mergeTwoLists = function(l1, l2) {
    if (l1 === null) return l2;
    if (l2 === null) return l1;
    if (l1.val < l2.val) {
        l1.next = mergeTwoLists(l1.next, l2);
        return l1;
    } else {
        l2.next = mergeTwoLists(l1, l2.next);
        return l2;
    }
};

K个一组翻转链表 25题

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。 k 是一个正整数,它的值小于或等于链表的长度。 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 示例: 给你这个链表:1->2->3->4->5

当 k = 2 时,应当返回: 2->1->4->3->5

当 k = 3 时,应当返回: 3->2->1->4->5 说明: 你的算法只能使用常数的额外空间。 你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。 题目情况解析【一个链表按k段k段翻转】 当k段能翻转==》就翻转 当不能翻转【前面的都反转完了 剩下的不足k个】==》直接加在后面 将【这一次】翻转得到新的【头部】和【上一次的尾部】相连接 当然也得记录【k+1项】因为如果直接翻转,则会丢失第【k+1项】 毕竟你反转后 屁股变成头了 找不到第【k+1项】 由第一部分析得

var reverseKGroup = function(head, k) {
  let root=null
  let rear=null
  while(reservable(head,k)){
    var arr=reserve(head,k)
    if(!root){
      root=arr[0]
      rear=arr[1]
    }else{
      rear.next=arr[0]
      rear=arr[1]
    }
    head=arr[2]
  }
  rear.next=head
  return root
};

//翻转操作
function reserve(head,k){
  if(k==1)
    return [head,head,head.next]
  var arr=reserve( head.next,k-1)
  arr[1].next=head
  return [arr[0],head,arr[2]]
}

//判断是否能翻转
function reservable(head,k){
  for(let i=k;i>0;i--){
    if(head==null)
      return false
    head=head.next
  }
  return true
}

链表两数相加 445

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。 进阶: 如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。

示例:

输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 8 -> 0 -> 7

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var addTwoNumbers = function(l1, l2) {
    if (!l1 || !l2) return;
    let lp1 = l1, lp2 = l2, s1 = []; s2 = [];
    while (lp1) {
        s1.push(lp1.val);
        lp1 = lp1.next;
    }
    while (lp2) {
        s2.push(lp2.val);
        lp2 = lp2.next;
    }
    let stack = [];
    let decimal = 0;
    while (s1.length || s2.length) {
        let sum = (s1.pop() || 0) + (s2.pop() || 0) + decimal;
        decimal = parseInt(sum / 10);
        sum = sum % 10;
        stack.push(sum);
    }
    if (decimal) {
        stack.push(1);
    }
    let res = {};
    let cur = res;
    while (stack.length) {
        cur.next = new ListNode(stack.pop());
        cur = cur.next;
    }
    return res.next;
};

字符串

最长不重复子字符串长度3

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。   请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
    if (s.length === 0 || s.length === 1) return s.length;
    let res = '';
    let stashRes = '';
    for(let i = 0; i < s.length; i++) {
        if (res.indexOf(s.charAt(i)) < 0) {
            res = res + s.charAt(i);
        } else if (res.charAt(0) === s.charAt(i)) {
            res = res.substring(1);
            res = res + s.charAt(i);
        } else {
            if (res.length > stashRes.length) stashRes = res;
            const index = res.indexOf(s.charAt(i));
            res = res.substring(index + 1) + s.charAt(i);
        }
    }
    return stashRes.length > res.length ?  stashRes.length : res.length;
};
字母异位词分组49

给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。

示例:

输入: ["eat", "tea", "tan", "ate", "nat", "bat"] 输出: [ ["ate","eat","tea"], ["nat","tan"], ["bat"] ] 说明:

所有输入均为小写字母。 不考虑答案输出的顺序。

/**
 * @param {string[]} strs
 * @return {string[][]}
 */

// 字母异位词 指字母相同,但排列不同的字符串。例如eat ate tea tae...
// 利用map数据结构。给strs中的每个单词都对应一个长度为26的数组(数组中的每个值为单词中各个英文字母出现的次数),数组中,索引0,1,2,3,4......分别对应a,b,c,d,e......,需要利用英文字母的ascii值做一下转换。利用这个数组记录单词中每个字母出现的次数,然后将这个数组转化为字符串,作为Map的键名,键值为字母出现次数相同的单词。最后遍历Map,把每个键值都push进结果数组中即可。
var groupAnagrams = function(strs) {
    
    if(!strs){
        return [];
    }

    let map =new Map();    //

    for(let str of strs){
        let char = new Array(26).fill(0);    //
        for(let i=0;i<str.length;i++){
            let ascii = str.charCodeAt(i)-97;//a对应ascii值为97 减去97即可转换为数组索引0,1...
            char[ascii]++;
        }
        let key = char.join("");

        if(map.has(key)){    //
            map.set(key,[...map.get(key),str])
        }else{
            map.set(key,[str]);
        }
    }

    let res = [];
    for(let [key,value] of map){    //
        res.push(value)
    }

    return res;
}