算法题集锦

115 阅读3分钟

1.无重复字符的最长子串 (双指针)

解题思路:

1.创建一个set = new Set(); 定义2个指针 i 和 j 、最大长度的变量 maxLength let [i, j, maxLength] = [0, 0, 0];

2.遍历字符串 for(i; i<s.length;i++)

3.判断set里面是否存在循环中的字符串 set.has(s[i]) 如果存在则 将字符串添加到set中 set.add(s[i]) , 并且 比较set的长度(set.size)和 maxLength的大小 (若set.size>maxLength,则将set.size赋值给maxLength, 即 maxLength = set.size)

4.如果循环中 set中存在这个字符串 则删除s[j], 并且j++;再次检查set是否存在s[i],如此反复 直到set里面没有s[i]为止,即 while(set.has(s[i])) { set.delete(s[j]); j++; } set.add(s[i]);

5.重复3和4的步骤,直到遍历完整个字符串

var lengthOfLongestSubstring = function(s) {
   let set = new Set();
   let [i,j,maxLength] = [0,0,0];
   if(s.length === 0) return 0;
   for(i;i<s.length;i++) {
     if(!set.has(s[i]))  {
        set.add(s[i]);
        maxLength = Math.max(maxLength, set.size);
     }else {
        while(set.has(s[i])) {
            set.delete(s[j]);
            j++;
        }
        set.add(s[i]);
     }
   }
   return maxLength;
}

2.两数相加 (单链表算法题)

输入: (2->4 -> 3)+ ( 5 -> 6 -> 4 ) 输出: 7 -> 0 -> 8 原因: 342 + 465 = 807

  1. 定义一个头节点 dummy = ListNode();
  2. 定义一个当前指针 curr,并且将curr指针指向头节点dummy 即 curr = dummy;
  3. 定义一个变量carry存储(进位的数即为十位上的数字 ,如:Math.floor(12/10) = 1 ;
  4. 开始while循环, 循环条件是 l1和l2 两个链表节点值不等于null 即 while(l1 !== null || l2!==null)
  5. 定义一个sum变量开始存储 节点之和
var addTwoNumbers = (l1,l2) {
    let dummy = new ListNode();
    let curr = dummy;
    let carry = 0;
    while(l1 !== null || l2 !== null) {
       let sum =0;
       if(l1.val) {
          sum += l1.val;
          l1 = l1.next;
      }
      if(l2.val) {
          sum += l2.val;
          l2 = l2.next;
      }
      sum += carry;
      curr.next = new ListNode(sum % 10);
      carry = Math.floor(sum / 10);
      curr = curr.next;
    }
    if(carry >0) {
       curr.next = new ListNode(carry);
    }
    return dummy.next;
}

3.两数之和

输入: nums = [2,7,11,15] ,target = 9; 因为 nums[0] + nums[1] = 9
输出: [0,1] 解题思路:

  1. 创建一个map
  2. for循环遍历nums数组
  3. 用target减 nums[i],以计算那个数能跟当前的数字相加得到target
  4. 检查map里有没有这个数,如果有则返回结果,如果没有则把num[i]当作key,放进map里
var twosums = function (nums, target) {
      let map = new Map();
      for(let i = 0;i<nums.length;i++) {
         let val = target - nums[i];
         if(map.has(val)) {
             return [map.get[val], i];
         }else {
            map.set(nums[i],i);
         }
      }
  return []; 
}

4.最长的回文字符串 (定义:从左边还是右边看 字符串都是一样的)

解题思路:

  1. 如果字符串长度小于2,则直接返回字符串

  2. 定义2个变量,一个是start存储当前找到的最大回文字符串的起始位置,另一个maxLength记录字符串的长度(终止位置就是start + maxLength)

  3. 创建一个helper function ,判断左边和右边是否越界,同时最左边的字符是否等于最右边的字符。 如果以上3个条件都满足,则判断是否需要更新回文字符串最大长度和最大字符串的起始位置。 然后left--; right++,继续判断,直到不满足3个条件之一;

  4. 遍历字符串,每个位置调用helper function两遍,第一遍检查i-1,i+1,第二遍检查i,i+1(为什么要检查2遍呢)

var longestPalindrome = funciton(s) {
  if(s.length <2) {
    return s;
  }
  let [start, maxLength]  = [0,1];
  function expandAroundCenter(left, right) {
    while(left>=0 && right< s.length && s[left] === s[right]) {
        if(right - left + 1 > maxLength) {
            maxLength = right - left +1;
            start = left;
        }
        left --;
        right ++;
    }
    for(let i = 0;i < s.length; i++) {
       expandAroundCenter(i-1,i+1);
       expandAroundCenter(i,i+1);
    }
   return s.subString(start,start+ maxLength);
  }
}

已知:1->2->4 1->3->4 (已知2个链表 按照从小到大的顺序将2链表合并成一个从小到大的新链表)

得到 1->1->2->3->4

解题思路:

1.创建一个dummy的空节点链表头 dummy = new ListNode();

2.定义一个指针 并将指针的指向dummy这个头节点

3.循环遍历了l1和l2两个链表 (判断条件是 循环过程中 l1 !== null && l2 !== null)

4.分别比较l1.val和l2.val值的大小 谁小就将curr.next指向较小的这个节点 ,最后将移动curr节点的next的域 (即 curr = curr.next)

5.当循环遍历完之后 分别判断l1!==null和l2!==null时,将curr的next的域指向当前不为空的链表

function newList(l1,l2) {
    let dummy = new ListNode();
    let curr = dummy;
    while(l1 !== null && l2 !== null) {
        if(l1.val < l2.val) {
            curr.next = l1;
            l1 = l1.next;
        }else {
            curr.next = l2;
            l2 = l2.next;
        }
        curr = curr.next;
    }
    if(l1 !== null) {
        curr.next = l1;
    }
    if(l2 !== null) {
        curr.next = l2;
    }
    return dummy.next;
}

已知 链表 1->2->3->4->5->6 两两交换 得到 2->1->4->3->6->5

解题思路:

  1. 创建一个dummy链表头节点(空节点)dummy = new ListNode();
  2. 创建一个指针p 并将dummy赋值给p指针
  3. 创建指针n1 = p.next 创建指针n2 = p.next.next;
  4. p.next = n2
  5. n1.next = n2.next;
  6. n2.next = n1
  7. p = n1;
function swapPairs(head) {
    let dummy = new ListNode();
    let p = dummy;
    p.next = head;
    while(p.next !== null && p.next.next !== null) {
        let n1 = p.next;
        let n2 = p.next.next;
        p.next = n2;
        n1.next = n2.next;
        n2.next = n1;
        p = n1;
    }
    return dummy.next;
}

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

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

解题思路:

  1. 检查数组是否为空数组
  2. 遍历所有字符串,将字母的出现频率放到数组对应的位置里(利用ASCII码)
  3. 建立一个长度为26的数组,起始值为0
  4. 遍历数组,安装相同字母出现频率进行分支归类(使用hashMap,即es6的 Map)
  5. 遍历map,将结果返回
function angramsGroup(str) {
    if(str.length === 0) {
        return [];
    }
    const map = new Map();
    for(const s of str) {
        const arr = Array(26).fill(0);
        for(let i = 0;i<s.length;i++) {
            const charactor = s.charCodeAt(i) - 97;
            arr[charactor]++;
        }
        const key = arr.join('');
        if(map.has(key)) {
           map.set(key,[...map.get(key),str]); 
        }else {
            map.set(key,[str]);
        }
    }
    let result = [];
    for(const item of map) {
        result.push(item[1]);
    }
    return result;
}

计算最大子序之和

function computedChildSums(arr) {
    let memo = [];
    memo[0] = arr[0];
    let max = memo[0];
    for(let i = 1;i < arr.length;i++) {
        memo[i] = Math.max([memo[i-1]+arr[i]], arr[i]);
        max = Math.max(memo[i], max);
    }
    return max;
}

矩阵的解法题

输入 : [ [1,2,3,4], [5,6,7,8], [9,10,11,12] ]

输出: [1,2,3,4,8,12,11,10,9,5,6,7]

矩阵解题思路:

1.判断数组是否为空,则返回空数组

2.定义6个变量分辨是数组的边界 left right top bottom left = 0;right = maxtric[0].length top = 0 bottom = mextric.length direction = 'right' 数组遍历的方向 result = [];

3.开始while循环 循环的判断条件是 left<=right top <= bottom;

4.while循环中分别有4个判断条件 分别是 1.direction === 'right' 2.direction === 'down' 3.direction === 'left' 4.direction === 'top' 且每个判断条件代表着数组遍历的方向,每个遍历的方向都要把数组的每一项添加到新的数组result中去;

①当 direction === 'right' 方向向右的时候,此时我们遍历矩阵数组maxtric, 执行 for(let i = left; i < right; i++) { result.push(maxtric[top][i]); } top++; direction = 'down';

②当direction === 'down' 方向向下的时候吗,此时遍历矩阵数组maxtric, 执行 for(let i = top; i <= bottom; i++) { result.push(maxtric[i])[right]; } right--; direction = 'left';

③当direction === 'left'方向向左的时候,此时遍历矩阵数组maxtric, 执行 for(let i = right;i<=left;i--) { result.push(maxtric[bottom][i]) } bottom--; direction = 'top';

④当direction === 'top',方向向上的时候,遍历矩阵数组maxtric, 执行 for(let i = bottom;i<=top;i--) { result.push(maxtric[i][left]); } left++; direction = 'right';

function maxtrcComputed(maxtric) {
    if(maxtric.length === 0) return [];
    let [left, right, top, bottom, direction, result] = [0, maxtric[0].length, 0, maxtric.length, 'right', []];
    while(left <= right && top<= bottom) {
        if(direction === 'right') {
            for(let i = left; i < right; i++) {
                result.push(maxtric[top][i]);
            }
            top++;
            direction = 'down';
        }else if(direction === 'down') {
            for(let i = top; i <= bottom; i++) {
                result.push(maxtric[i])[right];
            }
            right--;
            direction = 'left';
        }else if(direction === 'left') {
            for(let i = right;i <= left;i--) {
                result.push(maxtric[bottom][i]);
            }
            bottom--;
            direction = 'top';
        }else if(direction === 'top') {
            for(let i = bottom; i <= top; i--) {
                result.push(maxtric[i][left]);
            }
            left++;
            direction = 'right';
        }
    }
    return result;
}

合并区间算法题

已知:[[1,3],[2,6],[8,10],[12,15**]]**

输出: [[1,6],[8,10],[12,15]]

var merge = function(intervals) {
    if(intervals.length < 2) {
        return intervals;
    }
    //将intervals二维数组排序
    intervals.sort((a,b)=>{
        return a[0] - b[0];
    })
    let [curr, result] = [intervals[0],[]];
    for(const interval of intervals) {
        if(curr[1] >= interval[0]) {
            curr[1] = Math.max(curr[1], interval[1]);
            
        }else {
            result.push(curr);
            curr = interval;
        }
    }
    if(curr.length !== 0) {
        result.push(curr);
    }
    return result;
}