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
- 定义一个头节点 dummy = ListNode();
- 定义一个当前指针 curr,并且将curr指针指向头节点dummy 即 curr = dummy;
- 定义一个变量carry存储(进位的数即为十位上的数字 ,如:Math.floor(12/10) = 1 ;
- 开始while循环, 循环条件是 l1和l2 两个链表节点值不等于null 即 while(l1 !== null || l2!==null)
- 定义一个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]
解题思路:
- 创建一个map
- for循环遍历nums数组
- 用target减 nums[i],以计算那个数能跟当前的数字相加得到target
- 检查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.最长的回文字符串 (定义:从左边还是右边看 字符串都是一样的)
解题思路:
-
如果字符串长度小于2,则直接返回字符串
-
定义2个变量,一个是start存储当前找到的最大回文字符串的起始位置,另一个maxLength记录字符串的长度(终止位置就是start + maxLength)
-
创建一个helper function ,判断左边和右边是否越界,同时最左边的字符是否等于最右边的字符。 如果以上3个条件都满足,则判断是否需要更新回文字符串最大长度和最大字符串的起始位置。 然后left--; right++,继续判断,直到不满足3个条件之一;
-
遍历字符串,每个位置调用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
解题思路:
- 创建一个dummy链表头节点(空节点)dummy = new ListNode();
- 创建一个指针p 并将dummy赋值给p指针
- 创建指针n1 = p.next 创建指针n2 = p.next.next;
- p.next = n2
- n1.next = n2.next;
- n2.next = n1
- 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"] ]
解题思路:
- 检查数组是否为空数组
- 遍历所有字符串,将字母的出现频率放到数组对应的位置里(利用ASCII码)
- 建立一个长度为26的数组,起始值为0
- 遍历数组,安装相同字母出现频率进行分支归类(使用hashMap,即es6的 Map)
- 遍历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;
}