Frequently asked questions about data structures and algorithms (continuously updated...)

1. String

1. String transformation
description : For a string with a length of n, we need to do some transformations on it.
First, this string contains some spaces, just like "Hello World", and then what we need to do is to reverse the order of words separated by spaces in this string, and reverse the case of each character at the same time.
Example 1
input:
"This is a sample", 16
return value:
"SAMPLE A IS tHIS"

// 思路:
// 1. 将字符串用split(' ')按照空格符分割成数组
// 2. 将数组翻转,判断每一个项中每一个字母的大小写,如果是大写改为小写,如果是小写改为大写,生成一个新数组
// 3. 将新数组用join拼接成一个字符串
// 4. 注意:
//    split():默认按照空格分隔,会把多个空格当成一个分隔符。
//    split(' '):按照空格分隔,会把每一个空格都当成一个分隔符。
//    split(''):将每一个字符串都分隔。
const str = 'Hello World This Is a Student'
function trans(str, num){
    
    
  if(str.length != num)return '数组的长度有误!'
  const arrReverse = str.split(' ').reverse()
  return arrReverse.map(item => {
    
    
    // 进行大小写的转换
    return [...item].map(ele => ele == ele.toLowerCase() ? ele.toUpperCase() : ele.toLowerCase()).join('')
  }).join(' ')
}
console.log(trans(str,29))  // sTUDENT A iS tHIS wORLD hELLO


2. Description of the longest common prefix of strings : You are given a string array strs of size n, which contains n strings, write a function to find the longest common prefix in the string array, and return this common prefix.
Example 1
Input: ["abc"]
Return Value: "abc"
Example 2
Input: ["abca", "abc", "abca", "abc", "abcc"]
Return Value: "abc"

// 思路:
// 1. 如果数组长度为0,则返回空字符串
// 2. 如果数组长度为1,则返回数组中的字符串
// 3. 将数组排序,用第一个元素的第一个字符和最后一个元素的第一个字符进行比较
// 4. 如果相同将这个字符保存下来,以此类推将每次的字符串拼接起来,直到比较的两个字符串不相同,终止循环,最后返回拼接后的字符串
const strArr = ["abca","abc","abca","abc","abcc"]
function longestCommonPrefix(strArr){
    
    
  if(!strArr.length) return ''
  if(strArr.length === 1) return strArr[0]
  strArr.sort()
  const firstStr = strArr[0]
  const lastStr = strArr.pop()
  let res = ''
  for(let i=0;i<firstStr.length;i++){
    
    
    if(firstStr[i] == lastStr[i]){
    
    
      res += firstStr[i]
    }else{
    
    
      break
    }
  }
  return res
}

3. Verify the ip address
description : Given an ip address, determine whether it is an ip4 address or an ip6 address

An IPv4 address is represented by four groups of decimal numbers and dots, each address contains 4 decimal numbers ranging from 0 to 255, separated by (“.”). For example, 172.16.254.1;
at the same time, the number in the IPv4 address will not start with 0. For example, the address 172.16.254.01 is illegal.

An IPv6 address is represented by 8 groups of hexadecimal numbers, and each group represents 16 bits. These groups of numbers are separated by (":"). Only uppercase and lowercase characters and numbers from 0-9 are supported, special characters and spaces are not allowed

Example 1
Input: "172.16.254.1"
Return value: "IPv4"
Explanation: This is a valid IPv4 address, so return "IPv4"

Example 2
Input: "2001:0db8:85a3:0:0:8A2E:0370:7334"
Return value: "IPv6"
Explanation: This is a valid IPv6 address, so return "IPv6"

Example 3
Input: "256.256.256.256"
Return value: "Neither"
Explanation: This address is neither IPv4 nor IPv6 address

// 思路:
// 1. 对输入的字符串先判断是属于ipv4范畴的还是ipv6范畴的
// 2. 如果属于ipv4范畴进行ipv4的判定,如果属于ipv6范畴进行ipv6判定。否则直接返回 Neither
// 3. 对于ipv4的判定:
//   (1)先使用split('.')分割成数组,对数组长度判断,如果长度不为4,则返回 Neither。否则对数组里面的每一项是一个字符串进行判断
//   (2)如果字符串长度为0或者大于3则返回false,否则对字符串每一项判断
//   (3)如果字符串的第一项是'0'则返回false,否则如果不在'0'和'9'之间也返回false
//    (4) 将这个字符串转成数字,如果不在0-255之间返回false,否则返回true
// 4. 对于ipv6的判定:
//    (1) 先试用split(':')分割成数组,对数组长度判断,如果长度不为8,则返回 Neither,否则对数组里面的每一项是一个字符串进行判断
//    (2) 如果字符串长度为0或者大于4则返回false,否则对字符串每一项判断
//   (3)如果每一项的字符不在'0'--'9'、 'a'--'z' 、 'A'--'Z'之间则返回false,否则返回true

// 定义判断ipv4的方法:
function checkIPv4(s){
    
    
  if(s.length === 0 || s.length > 3) return false
  if(s[0] === '0') return false
  for(let i of s){
    
    
    if(i > '9' || i < '0') return false
  }
  return Number(s) <= 255 && Number(s) > 0
}

// 定义判断ipv6的方法:
function checkIPv6(s){
    
    
  if(s.length === 0 || s.length > 4) return false
  for(let j of s){
    
    
    if(!(j>='0' && j<='9' || j>='a' && j<='f' || j>='A' && j<='F')) return false
  }
  return true
}

function solve(IP){
    
    
  if(IP.indexOf('.') != -1){
    
    
    const arrIpv4 = IP.split('.')
    if(arrIpv4.length != 4) return 'Neither'
    for(let ip of arrIpv4){
    
    
      if(!checkIPv4(ip)){
    
    
        return 'Neither'
      }
    }
    return 'IPv4'
  }else if(IP.indexOf(':') != -1){
    
    
    const arrIpv6 = IP.split(':')
    if(arrIpv6.length != 8) return 'Neither'
    for(let ip of arrIpv6){
    
    
      if(!checkIPv6(ip)){
    
    
        return 'Neither'
      }
    }
    return 'IPv6'
  }else{
    
    
    return 'Neither'
  }
}


4. Description of addition of large numbers : read in two numbers in the form of a string, write a function to calculate their sum, and return it in the form of a string.
Data range : the length is less than or equal to 100000, and the string is only composed of '0'-'9'
Requirements : time complexity O(n)

Example 1
Input: "1", "99"
Return value: "100"
Explanation: 1+99=100

Example 2
input: "114514", ""
return value: "114514"

// 思路:
// 1. 对于一个很大的数来说不可以直接采用 Number()转成数字再相加,再用String(),因为这时候会丢失精度
// 2. 当两个数位数不一样的时候,分割成数组,在小的那个数前面补位'0',直到对齐
// 3. 从后往前加,做进位处理。如果大于9,则取余数,将余数用unshift()放进一个空数组的前面。同时记录一个变量为1。下次相加的时候加上这个变量
//    如果不大于9,则将这个数放进数组的前面
// 4. 最后将得到的数组用join()方法拼接成一个字符串
function solve(s,t){
    
    
  const arr1 = s.split('')
  const arr2 = t.split('')
  let resArr = [], go = 0
  while(arr1.length || arr2.length){
    
    
    let num1 = +arr1.pop() || 0
    let num2 = +arr2.pop() || 0
    let temp = num1 + num2 + go
    if(temp > 9){
    
    
      temp %= 10
      go = 1
    }else{
    
    
      go = 0
    }
    resArr.unshift(temp)
  }
  if (go) resArr.unshift(1);
  return resArr.join('')
}

2. Heap, stack, queue

1. Use two stacks to implement queue
description : use two stacks to implement a queue, and use n elements to complete the function of inserting an integer (push) at the end of the queue n times and deleting an integer (pop) at the head of the queue n times. The elements in the queue are of type int. Ensure that the operation is legal, that is, ensure that there are elements in the queue when the pop operation is performed.
Data range : n<=1000
Requirements : The space complexity of storing n elements is O(n), and the time complexity of insertion and deletion is O(1)
Example 1
Input: ["PSH1", "PSH2", " POP", "POP"]
return value: 1, 2
Description: BinarySearchTree
"PSH1": means insert 1 into the end of the queue
"PSH2": means insert 2 into the end of the queue
"POP": means delete an element, first in first out => Return 1
"POP": means to delete an element, first in first out => return 2

// 方法一:
// 思路:
// 1. 定义两个空栈
// 2. 将数字push进第一个栈,然后再将pop出来的值push进第二个栈。最后在pop出来
// let arr2 = [],
//       arr1 = [];
// function push(node)
// {
    
    
//     // write code here
//     arr1.push(node);
// }
// function pop()
// {
    
    
//     // write code here
//     if(!arr2.length){
    
    
//         while(arr1.length){
    
    
//             arr2.push(arr1.pop())
//         }
// }
//         return arr2.pop();
// }

// 方法二:
// 思路:
// 1. 定义一个空栈
// 2. 先将值push进去,然后再shift从头部删除值
let queue = [];
function push(node)
{
    
    
  return queue.push(node);
}
function pop()
{
    
    
  return queue.shift();
}


2. Stack description including the Min function : define the data structure of the stack, please implement a min function in this type that can get the smallest element contained in the stack, and ensure that when the pop, top and min functions are operated during input operations, there must be a certain amount in the stack There are elements.

The methods contained in this stack are:
push(value): push value into the stack
pop(): pop the top element of the stack
top(): get the top element of the stack
min(): get the smallest element in the stack

Example :
Input: ["PSH-1", "PSH2", "MIN", "TOP", "POP", "PSH1", "TOP", "MIN"] Output: -1,2,1,
-1
Analysis:
"PSH-1" means to push -1 into the stack, and the element in the stack is -1
"PSH2" means to push 2 into the stack, and the element in the stack is 2, -1
"MIN" means to get the stack at this time The smallest element ==> return -1
"TOP" means to get the top element of the stack ==> return 2
"POP" means pop the top element of the stack, pop 2, the element in the stack is -1
"PSH1" means push 1 into the stack, The element in the stack is 1, -1
"TOP" means to get the top element of the stack ==> return 1
"MIN" means to get the smallest element in the stack at this time ==> return -1

// 思路:
// 1. 定义一个空栈
// 2. top函数获取的就是栈中最后一个元素
// 3. min函数获取就是栈中元素的最小值,可以使用Math.min()方法
let stack = []
function push(node)
{
    
    
  return stack.push(node)
}
function pop()
{
    
    
  if(stack.length){
    
    
    return stack.pop()
  }
}
function top()
{
    
    
  return stack[stack.length - 1]
}
function min()
{
    
    
  return Math.min(...stack)
}

3. Valid bracket sequence
description : Given a string containing only the characters '(',')','{','}','['and']', determine whether the given string is legal The bracket sequence, the bracket must be closed in the correct order, "()" and "()[]{}" are legal bracket sequences, but "(]" and "([)]" are not legal. Data
range : String length 0 <= n <= 10000
Requirements : space complexity O(n), time complexity O(n)

Example 1
Input: "["
Return value: false

Example 2
Input: "[]"
Return value: true

// 思路:
// 1. 先判断字符串的长度是不是偶数,如果是奇数则一定匹配不成功直接返回false
// 2. 如果长度是偶数,定义一个空栈,从左往右遍历字符串,遇到左字符串则放进栈中
// 3. 继续遍历如果遇到右字符串立刻从栈中弹出一个字符串,如果二者不能匹配则返回false
// 4. 遍历结束后如果栈的长度为零则说明匹配成功,是有效括号序列,返回true
function isValid( s ) {
    
    
  const len = s.length % 2
  let stack = []
  if(len) return false
  for(let i of s){
    
    
    if(i=='(' || i=='[' || i=='{'){
    
    
      stack.push(i)
    }else{
    
    
      if(stack.length){
    
    
        if(i==')'){
    
    
          if(stack.pop() != '(') return false
        }else if(i==']'){
    
    
          if(stack.pop() != '[') return false
        }else{
    
    
          if(stack.pop() !='{') return false
        }
      }else{
    
    
        // 说明没有左括号,肯定匹配不成功
        return false
      }
    }
  }
  return !stack.length
}


4. Description of the maximum value of the sliding window : given an array num of length n and the size of the sliding window, find the maximum value of all values ​​in the sliding window.
For example, given the array [1,2,3], the window size is 2. Then all sliding results may be [1,2], [2,3], so the corresponding maximum value is [2,3]
Example 1
input: [2,3,4,2,6,2,5,1 ],3
return value: [4,4,6,6,6,5]

Example 2
input: [9,10,9,-7,-3,8,2,-6], 5
return value: [10,10,9,8]

Example 3
input: [1,2,3,4], 5
return value: []

// 方法一思路:
// 1. 判断窗口长度和数组长度的大小,窗口长度为0,或者数组长度为0,或者窗口长度大于数组长度,返回空数组
// 2. 确定可能出现的滑动结果即有几组值,n = len - size + 1(n:滑动窗口值,len:数组长度,size:窗口大小)
// 3. 遍历数组,记录所有的滑动窗口,并计算出每一个窗口中的最大值
// 4. 将记录的最大值push进入一个新的栈中,最后返回这个栈
function maxInWindows( num ,  size ) {
    
    
  if(!size || size > num.length) return []
  const endValue = num.length - size
  let maxNum = []
  let stack = []
  for(let i=0;i<endValue+1;i++){
    
    
    for(let j=i;j<i+size;j++){
    
    
      stack.push(num[j])
    }
    const max = Math.max(...stack)
    maxNum.push(max)
    stack = []
  }
  return maxNum
}

// 方法二思路:
// 1. 判断窗口长度和数组长度的大小,窗口长度为0,或者数组长度为0,或者窗口长度大于数组长度,返回空数组
// 2. 新建两个空栈 stack 和 maxNum 遍历数组将每一项放进 stack 中,判断 stack 的长度
//    如果 stack 的长度等于 size,此时求取 stack 中的最大值,放进 maxNum 中
//    如果 stack 的长度大于 size,此时从 stack 中删除第一个元素,此时 stack 的长度会等于 size,在求取 stack 中的最大值放进 maxNum 中
// 3. 遍历结束后返回 maxNum
function maxInWindows( num ,  size ){
    
    
  if(!num.length || !size || size > num.length) return []
  let stack = [],maxNum = []
  for(let i of num){
    
    
    stack.push(i)
    if(stack.length > size){
    
    
      stack.shift()
    }
    if(stack.length == size){
    
    
      maxNum.push(Math.max(...stack))
    }
  }
  return maxNum
}


5. Description of the smallest k numbers : Given an array of length n that may have duplicate values, find the smallest k numbers that do not remove duplicates. For example, the array elements are 8 numbers 4, 5, 1, 6, 2, 7, 3, 8, and the smallest 4 numbers are 1, 2, 3, 4 (in any order).
Example 1
Input: [4,5,1,6,2,7,3,8],4
Return value: [1,2,3,4]
Explanation: Return the smallest 4 numbers, return [1, 3,2,4] also works

Example 2
input: [1], 0
return value: []

Example 3
input: [0,1,2,1,2], 3
return value: [0,1,1]

// 思路:
// 1. 将数组从小到大排序
// 2. 新建一个空栈,从排序后的数组中 shift 出前 k 个数
function GetLeastNumbers_Solution(input, k){
    
    
  if(!input.length || !k) return []
  let stack = []
  input.sort((a,b) => a-b)  // 从小到大排个序,会改变原数组
  for(let i=0;i<k;i++){
    
    
    stack.push(input.shift())
  }
  return stack
}

6. Find the Kth largest number
Description : There is an array of integers, please find the kth largest number in the array according to the idea of ​​quick sort. Given an integer array a, given its size n and the k you want to find, please return the kth largest number (including repeated elements, no need to remove duplicates), and ensure that the answer exists

Example 1
input: [1,3,5,2,2],5,3
return value: 2

Example 2
Input: [10,10,9,9,8,7,5,6,4,3,4,2],12,3
Return value: 9
Explanation: The third largest after deduplication is 8, but This question requires repeated elements and does not need to be deduplicated, so output 9

// 思路:
// 1. 先判断数组长度是否为零,数组长度和n,k的大小关系。如果数组长度为零,或者数组长度不等于n,或者小于k。都返回false
// 2. 将数组从大到小排列,从中取出第k个数
function findKth( a ,  n ,  K ) {
    
    
  if(!a.length || a.length != n || a.length < K ) return false
  a.sort((a,b) => b-a)  // 从大到小排列
  return a[K-1]
}

7. Find the median
Description : / How to get the median in a data stream? If an odd number of values ​​are read from the data stream, the median is the value in the middle of all values ​​sorted. If an even number of values ​​are read from the data stream, the median is the average of the middle two numbers after all the values ​​are sorted.

Example 1
Input: [5,2,3,4,1,6,7,0,8]
Return value: "5.00 3.50 3.00 3.50 3.00 3.50 4.00 3.50 4.00 "
Explanation: The data stream continuously spits out 5,2, 3..., the averages obtained are 5, (5+2)/2, 3...

Example 2
Input: [1,1,1]
Return value: "1.00 1.00 1.00 "

// 思路:
// 1. 如果是一个空数组,直接返回'',
// 2. 新建一个数组,把原数组中的头部元素逐一取出放进这个数组中。在放进之后对数组进行从小到大的排序,排序完对数组长度判断
//    如果长度是奇数,则取中间值。如果长度是偶数则取中间两个值的平均值,就是中位数
// 3. 将上面得到中位数再放进一个新的栈中
// 4. 用join(' ')的方法拼成一个字符串


// 读取数据流
function Insert(num)
{
    
    
  if(!num.length) return ''
  let stack1 = [],stack2 = []
  for(let i=0;i<num.length;i++){
    
    
    stack1.push(num[i]) // 取出num中的头部元素放进stack1中
    stack1.sort((a,b)=>a-b)  // 对stack1进行从小到大排序
    const median = GetMedian(stack1)
    stack2.push(median)
  }
  return stack2.join(' ')
}

// 获取当前数据流中的中位数
function GetMedian(arr){
    
    
	if(arr.length % 2){
    
    
    // 此时数组长度为奇数,中位数是中间的值
    const index = Math.floor(arr.length / 2)
    const value = arr[index]
    return value.toFixed(2)
  }else{
    
    
    // 此时数组长度是偶数,中位数是中间两个值的平均值
    const index = arr.length / 2
    const value = (arr[index] + arr[index - 1]) / 2
    return value.toFixed(2)
  }
}

8. Expression evaluation
description : Please write an integer calculator that supports addition, subtraction, multiplication and parentheses.
Requirements : Space Complexity: O(n), Time Complexity: O(n)

Example 1
Input: "1+2"
​​Return value: 3

Example 2
Input: "(2*(3-4))*5"
Return value: -10

Example 3
Input: "3+2 3 4-1"
Return value: 26

function solve( s ) {
    
    
  // write code here
  return eval(s)
}

3. Hash


1. Description of the sum of two numbers : Given an integer array numbers and a target value target, please find the subscripts of two numbers that add up to the target value in the array, and the returned subscripts are arranged in ascending order.
Requirements : space complexity O(n), time complexity O(nlogn)

Example 1
Input: [3,2,4],6
Return value: [2,3]
Explanation: Because 2+4=6, and the subscript of 2 is 2, and the subscript of 4 is 3, and because the subscript 2 < subscript 3, so return [2,3]

Example 2
Input: [20,70,110,150],90
Return value: [1,2]
Explanation: 20+70=90

function twoSum(numbers, target) {
    
    
  if(!numbers.length) return false
  const map = new Map()
  for(let i=0; i<numbers.length; i++) {
    
    
    if(map.has(target-numbers[i])) {
    
    
      return [map.get(target-numbers[i]) + 1, i + 1]
    }else {
    
    
      map.set(numbers[i], i)
    }
  }
}


2. Description of numbers that appear more than half of the time in the array : Given an array of length n, there is a number in the array that appears more than half of the length of the array, please find this number.
Requirements : space complexity: O(1), time complexity O(n)

Example 1
input: [1,2,3,2,2,2,5,4,2]
return value: 2

Example 2
input: [3,3,3,3,2,2,2]
return value: 3

Example 3
Input: [1]
Return value: 1

// 方法一思路:
// 1. 建立一个空对象,将数组中的每一项作为对象中的key,出现次数作为值。(利用了对象中key的唯一性)
// 2. 如果这个值第一次出现就将他的值设为1,后面再出现一次,就将这个值加上1。和数组长度的一半向下取值比较
// 3. 如果小于,继续循环;如果大于终止循环,返回当前的key

// 使用一般 for 循环
// const arr = [1,2]
function MoreThanHalfNum_Solution( numbers ) {
    
    
  const len = Math.floor(numbers.length / 2 )
  let obj = {
    
    }
  if(numbers.length == 1){
    
    
    return numbers[0]
  }else{
    
    
    for(let i of numbers){
    
    
      if(obj[i]){
    
    
        obj[i]++
        if(obj[i] > len){
    
    
          return i
        }
      }else{
    
    
        obj[i] = 1
      }
    }
    return '无解'
  }
} 
// console.log(MoreThanHalfNum_Solution(arr));

// 使用reduce
// const arr = [3,3,3,3,2,2,2]
function MoreThanHalfNum_Solution(numbers){
    
    
  const len = Math.floor(numbers.length / 2 )
	if(numbers.length == 1) return numbers[0]
	const obj = numbers.reduce((preValue,curValue)=>{
    
    
		preValue[curValue] = (preValue[curValue] + 1) || 1
		return preValue
	},{
    
    })
  for(let i in obj){
    
    
    if(obj[i] > len) return i
  }
  return '无解'
}
// console.log(MoreThanHalfNum_Solution(arr));

// // 方法二:思路
// 将数组从小到大排列,取中那个数
// 如果这个数在数组中出现次数超过了一半,则排序后中间的那个数就是要求的结果
const arr = [3,3,3,3,2,2,2]
function MoreThanHalfNum_Solution(numbers){
    
    
  const len = Math.floor(numbers.length / 2 )
  return numbers.sort((a,b) => a -b)[len]
}
console.log(MoreThanHalfNum_Solution(arr));


3. Description of two numbers that only appear once in an array : In an integer array, except for two numbers that only appear once, other numbers appear twice. Please write a program to find these two numbers that appear only once.
Requirements : space complexity O(1), time complexity O(n), the output results are arranged in non-descending order

Example 1
Input: [1,4,1,6]
Return value: [4,6]
Explanation: The smaller number in the returned results is ranked first

Example 2
input: [1,2,3,3,2,9]
return value: [1,9]

// 方法一思路:
// 1. 新建一个对象 obj 和一个数组 arr
// 2. 将数组中的每一项作为对象中的key,出现次数作为值。(利用了对象中key的唯一性)
// 3. 统计每个数字出现的次数,然后对obj里面的每一项进行判断,如果对应的值为1,则将这个键放入arr数组中
// 4. 将最后得到的arr数组按照从小到大的顺序进行排列
function FindNumsAppearOnce(nums){
    
    
  let obj = {
    
    }, arr = []
  for(let i of nums){
    
    
    if(obj[i]){
    
    
      obj[i]++
    }else{
    
    
      obj[i] = 1
    }
  }
  for(let j in obj){
    
    
    if(obj[j] == 1){
    
    
      arr.push(+j)
    }
  }
  return arr.sort((a,b) => a-b)
}

// 方法二思路:
// 1. 新建一个数组 arr 用于存储返回的结果
// 2. 如果这个数字在数组中只出现了一次,那么从头开始找和从尾开始找得到的应该是同一个数组下标
// 3. 所以判断indexOf() 和 lastIndexOf() 返回的下标是否相同,如果相同将这个值 push 进入 arr 中
// 4. 将得到的数组按照从小到大的顺序排列
function FindNumsAppearOnce(nums){
    
    
  let arr = []
  for(let i of nums){
    
    
    if(nums.indexOf(i) == nums.lastIndexOf(i)){
    
    
      arr.push(i)
    }
  }
  return arr.sort((a,b) => a-b)
}


4. Description of the missing first positive integer : Given an integer array nums with no repeated elements, please find the smallest positive integer that does not appear in it.
Requirements : Space complexity O(1), time complexity O(n )

Example 1
Input: [1,0,2]
Return value: 3

Example 2
input: [-2,3,4,1,5]
return value: 2

Example 3
input: [4,5,6,8,9]
return value: 1

// 思路:
// 1. 将数组用set转换,使用while循环,终止条件是取到数组的长度。
// 2. 使用has()判断当前值是否在set数据结构中,不在则返回这个值,在则将当前值加1
function minNumberDisappeared( nums ) {
    
    
  // 会超时
  // if(!nums.length) return 1
  // let i = 1
  // while(i <= nums.length){
    
    
  //   if(!nums.includes(i)){
    
    
  //     return i
  //   }else{
    
    
  //     i++
  //   }
  // }
  // return i

  let set = new Set(nums);
  let i = 1;
  if(!nums.length) return 1
  while(i <= nums.length){
    
    
    if(!set.has(i)){
    
    
      return i
    }else{
    
    
      i++;
    }
  }
  return i;
}


5. Description of the sum of three numbers : Given an array S with n elements, is there any element a, b, c in S that satisfies a+b+c=0? Find all triples in array S that satisfy the condition.
Requirements : Space Complexity: O(n2), Time Complexity O(n2)
Note : The elements in the triplet (a, b, c) must be in non-descending order. (i.e. a≤b≤c) the solution set cannot contain repeated triplets.

Example 1
Input: [0]
Return value: []

Example 2
input: [-2,0,1,1,2]
return value: [[-2,0,2],[-2,1,1]]

Example 3
input: [-10,0,10,20,-10,-40]
return value: [[-10,-10,20],[-10,0,10]]

// 思路:
// 1. 如果数组长度小于3,直接返回空数组 []
// 1. 先将原数组按照从小到大的顺序排序
// 2. 定义一个新数组 array 用来存储满足条件的结果
// 3. 在排序后的数组中遍历,设定两个值,一个是 head = i+1,一个是tail = 数组长度 -1
// 4. 执行一个while循环,循环条件是head < tail
// 5. 对当前值,head 和 tail 指向的值做一个求和操作。对求和结果判断,如果结果为 0,则将这三个值放进一个数组中并push进 array 中同时则将 haed +1 向后移一位,tail - 1向前移动一位。
// 如果大于零则将 tail - 1,如果小于零则将 head + 1
// 6. 对循环结束后得到的 array 数组,进行二维数组的去重操作。
// 7. 二维数组去重
//  (1)将里面的每一项用 JSON.stringify 变为字符串
//  (2)将上述结果用 new Set() 去重,在将结果里面的每一项用 JSON.parse()反转回去

function threeSum( num ) {
    
    
  let len = num.length
  if(len < 3) return []
  let arr = []
  num.sort((a,b) => a -b)
  for(let i=0;i<len - 2;i++){
    
    
    let head = i + 1, tail = len - 1
    while(head < tail){
    
    
      let sum = num[i] + num[head] + num[tail]
      if(sum > 0){
    
    
        tail--
      }else if(sum < 0){
    
    
        head++
      }else{
    
    
        arr.push([num[i], num[head], num[tail]])
        head++
        tail--
      }
    }
  }
  // 对 array 数组,进行二维数组的去重操作
  let stringArr = arr.map(item => JSON.stringify(item))
  let setArr = [...new Set(stringArr)]
  let resultArr = setArr.map(ele => JSON.parse(ele))
  return resultArr
}
console.log(threeSum([-2,0,1,1,2]));

Four. Linked list

1. Reverse linked list
Description: Given a single linked list head node pHead (the head node has a value, for example, its val is 1), the length is n, after reversing the linked list, return a new linked list.

Example 1
Input: {1,2,3}
Return value: {3,2,1}

Example 2
Input: {}
Return value: {}
Explanation: If the linked list is empty, the output is empty

// 思路:
// 1. 定义两个指针,一个 pre 指向 null,一个 cur 指向当前表头
// 2. 将cur.next存起来,因为是单链表,不保存的话,改变方向之后就找不到旧节点的下个节点了
// 3. 直接改变链表方向,将cur.next 指向 pre。
// 4. 将 pre 和 cur 逐渐向后面移动,直到 cur 指向 null,此时返回 pre
function ReverseList( head ) {
    
    
  // write code here
  let pre = null
  let cur = head
  while(cur){
    
    
    let temp = cur.next
    cur.next = pre
    pre = cur
    cur = temp
  }
  return pre
}

2. Reversal within the specified area

Five. Binary tree

1. Front, middle and back traversal of binary tree

// 一. 前序遍历:根左右
// 描述:给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
// 输入:{1,#,2,3}
// 返回值:[1,2,3]

/*
 * function TreeNode(x) {
 *   this.val = x;
 *   this.left = null;
 *   this.right = null;
 * }
 */
 
// 思路:
// 1. 先判断是否为空二叉树
// 2. 递归遍历左右子树
function preorderTraversal( root ) {
    
    
  let res = []
  function preorder(node){
    
    
    if(!node) return 
    res.push(node.val)
    preorder(node.left)
    preorder(node.right)
  }
  preorder(root)
  return res
}

// 二. 中序遍历:左根右
// 描述:给你二叉树的根节点 root ,返回它节点值的 中序 遍历。
// 输入:{1,2,#,#,3}
// 返回值:[2,3,1]
function inorderTraversal( root ) {
    
    
  let res = []
  function inorder(node){
    
    
    if(!node) return 
    inorder(node.left)
    res.push(node.val)
    inorder(node.right)
  }
  inorder(root)
  return res
}



// 三. 后序遍历:左右根
// 描述:给定一个二叉树,返回他的后序遍历的序列。
// 输入:{1,#,2,3}
// 返回值:[3,2,1]
function postorderTraversal( root ) {
    
    
  let res = []
  function postorder(node){
    
    
    if(!node) return 
    postorder(node.left)
    postorder(node.right)
    res.push(node.val)
  }
  postorder(root)
  return res
}


2. Description of level order traversal of binary tree : Given a binary tree, return the result of level order traversal of the binary tree (from left to right, traversing layer by layer)
Requirements : 0 <= node number of binary tree <= 1500

Example 1 :
Input: {3,9,20,#,#,15,7}
Output: [[3], [9, 20], [15, 7]]

Example 2
Input: {1,2}
Return value: [[1],[2]]

Example 3
input: {1,2,3,4,#,#,5}
return value: [[1],[2,3],[4,5]]

// 思路:
// 1. 如果是空二叉树返回一个空数组
// 2. 新建两个数组 res = [](用来存储最终的结果),queue = [root](用来存储每一层的结果)
// 3. 当 queue 这个数组的长度不为零时候,通过while循环将每一层的数据放入 queue 中。
// 4. 将 queue 这个数组放入 res 中。对左右子树依然执行步骤三
function levelOrder( root ) {
    
    
  if(!root) return []
  let res = [], queue = [root]
  while (queue.length) {
    
    
    res.push(queue.map(node => node.val));
    queue = queue.reduce((q, node) => {
    
    
      node.left && q.push(node.left);
      node.right && q.push(node.right);
      return q;
    }, []);
  }
  return res;
}


3. Print the binary tree description in zigzag order : Given a binary tree, return the zigzag layer order traversal of the binary tree (the first layer is from left to right, the next layer is from right to left, and always alternate like this)

Example 1
Input: {1,2,3,#,#,4,5}
Return value: [[1],[3,2],[4,5]]
Explanation: As explained in the title, the first layer is the root Nodes, print results from left to right, right to left for the second layer, and left to right for the third layer.

Example 2
input: {8,6,10,5,7,9,11}
return value: [[8],[10,6],[5,7,9,11]]

Example 3
Input: {1,2,3,4,5}
Return value: [[1],[3,2],[4,5]]

// 思路:按照层序遍历的方式,将偶数项翻转排列,层序遍历的思路见上
function Print( pRoot ) {
    
    
  if(!pRoot) return []
  let res = [], queue = [pRoot], floor = 1;
  while(queue.length){
    
    
    // 判断是奇数层还是偶数层,如果是奇数层直接放入数组中,如果是偶数层先反转一下再放进数组中
    if(floor % 2 == 1){
    
    
      // 奇数层
      res.push(queue.map(node => node.val))
    }else{
    
    
      // 偶数层
      res.push(queue.map(node => node.val).reverse())
    }
    queue = queue.reduce((q, node) => {
    
    
      node.left && q.push(node.left);
      node.right && q.push(node.right);
      return q;
    }, [])
    floor++
  }
  return res
}

Guess you like

Origin blog.csdn.net/du_aitiantian/article/details/132151605