算法汇集

4 篇文章 0 订阅

Reverse Integer

Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231, 231 − 1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.
JS实现

function reverse(x) {
  const result = parseInt([...String(x)].reverse().join(''), 10);
  if (result > 0x7FFFFFFF) return 0;
  return result * Math.sign(x);
}

GO实现

var MIN int = 0x80000000
var MAX int = 0x7FFFFFFF
func reverse(x int) int {
    sum := 0
    for {
        leftDigits := x/10
        rightDigit := x%10
        x = leftDigits
        sum = sum * 10 + rightDigit;
        if 0 == leftDigits {
            break;
        }
    }
    if sum < -MIN || sum > MAX {
        return 0
    }
    return sum
}

Palindrome Number

JS

const reverse = function (x) {
    let rev = 0
    while (x) {
        rev = rev * 10 + x % 10
        x = parseInt(x / 10, 10)
    }
    return rev
}
/**
 * @param {number} x
 */
const isPalindrome = function (x) {
    if (x < 0 || (x % 10 === 0 && x !== 0)) {
       return false
    }
    return x === reverse(x)
}

GO

func isPalindrome(x int) bool {
    if x < 0 || (x % 10 == 0 && x != 0) {
        return false
    }
    primeX := x
    rev := 0
    for x > 0 {
        rev = rev * 10 + x % 10
        x /= 10
    }
    return rev == primeX
}

3Sum Closest

Given an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

JS

function abs(a) {
    return a > 0 ? a : -a;
}
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var threeSumClosest = function (nums, target) {
    let n = nums.length;
    let res = 0;
    let diff = Number.MAX_SAFE_INTEGER
    if (n > 2) {
        nums.sort((a, b) => {
            return a - b;
        });
        for (let i = 0; i < n - 2; i++) {
            let j = i + 1;
            let k = n - 1;
            while(j < k) {
                let sum = nums[i] + nums[j] + nums[k];
                if (abs(sum - target) < diff) {
                    res = sum;
                    diff = abs(sum-target);
                }
                if (sum === target) {
                    return res;
                } else if (sum > target) {
                    k--;
                } else {
                    j++;
                }
            }
        }
    }
    return res;
}

GO

// O(n^2)
func threeSumClosest(nums []int, target int) int {
	n, res, diff := len(nums), 0, math.MaxInt32
	if n > 2 {
		sort.Ints(nums)
		for i := 0; i < n-2; i++ {
			for j, k := i+1, n-1; j < k; {
				sum := nums[i] + nums[j] + nums[k]
				if abs(sum-target) < diff {
					res, diff = sum, abs(sum-target)
				}
				if sum == target {
					return res
				} else if sum > target {
					k--
				} else {
					j++
				}
			}
		}
	}
	return res
}

3Sum

GO

用 map 提前计算好任意 2 个数字之和,保存起来,可以将时间复杂度降到 O(n^2)。这一题比较麻烦的一点在于,最后输出解的时候,要求输出不重复的解。数组中同一个数字可能出现多次,同一个数字也可能使用多次,但是最后输出解的时候,不能重复。例如 [-1,-1,2] 和 [2, -1, -1]、[-1, 2, -1] 这 3 个解是重复的,即使 -1 可能出现 100 次,每次使用的 -1 的数组下标都是不同的。

这里就需要去重和排序了。map 记录每个数字出现的次数,然后对 map 的 key 数组进行排序,最后在这个排序以后的数组里面扫,找到另外 2 个数字能和自己组成 0 的组合。

package leetcode

import (
	"sort"
)

func threeSum(nums []int) [][]int {
	res := [][]int{}
	counter := map[int]int{}
	for _, value := range nums {
		counter[value]++
	}

	uniqNums := []int{}
	for key := range counter {
		uniqNums = append(uniqNums, key)
	}
	sort.Ints(uniqNums)

	for i := 0; i < len(uniqNums); i++ {
		if (uniqNums[i]*3 == 0) && counter[uniqNums[i]] >= 3 {
			res = append(res, []int{uniqNums[i], uniqNums[i], uniqNums[i]})
		}
		for j := i + 1; j < len(uniqNums); j++ {
			if (uniqNums[i]*2+uniqNums[j] == 0) && counter[uniqNums[i]] > 1 {
				res = append(res, []int{uniqNums[i], uniqNums[i], uniqNums[j]})
			}
			if (uniqNums[j]*2+uniqNums[i] == 0) && counter[uniqNums[j]] > 1 {
				res = append(res, []int{uniqNums[i], uniqNums[j], uniqNums[j]})
			}
			c := 0 - uniqNums[i] - uniqNums[j]
			if c > uniqNums[j] && counter[c] > 0 {
				res = append(res, []int{uniqNums[i], uniqNums[j], c})
			}
		}
	}
	return res
}

JS

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    const res = [];
    let numsMap = new Map();
    nums.forEach(a => {
        let value = numsMap.get(a)
        !!value ? numsMap.set(a, ++value) : numsMap.set(a, 1)
    })
    let m = Array.from(numsMap.keys())
    m.sort((a, b) => {
        return a - b
    });
    for (i = 0; i < m.length; i++) {
        if (m[i] * 3 == 0 && numsMap.get(m[i]) >= 3) {
            res.push([m[i], m[i], m[i]]);
        }
        for (let j = i+1; j < m.length; j++) {
            if ((m[i] * 2 + m[j]) === 0 && numsMap.get(m[i]) > 1) {
                res.push([m[i], m[i], m[j]])
            }
            if ((m[j] * 2 + m[i]) === 0 && numsMap.get(m[j]) > 1) {
                res.push([m[i], m[j], m[j]])
            }
            let c = 0 - m[i] -m[j]
            if (c > m[j] && numsMap.get(c)) {
                res.push([m[i], m[j], c])
            }
        }
    }
    return res;
};

快速排序+递归

对数组求和
function sum (arr) {
  if (arr.length === 0) return 0;
  let first = arr[0];
  arr.shift();
  return first + sum(arr);
}
console.log(sum([1,2,3,4,5,6,7,8,9,10]))
找出数组中最大的一位
function max (list) {
  if (list.length === 1) return list[0];
  if (list.length === 2) {
    return list[0] > list[1] ? list[0] : list[1]
  }
  const temp = list[0];
  list.shift();
  const submax = max(list);
  return temp > submax ? temp : submax;
}
console.log(max([9002,1,899,4,5,23,99]))

下面是go的实现法

package main
import (
    "fmt"
)
func maxChild(a []int) int {
	if len(a) == 1 {
		return a[0]
	}
	if len(a) == 2 {
		if a[1] > a[0] {
			return a[1]
		}
		return a[0]
	}
	biggest := a[0]
	a = append(a[:0], a[1:]...)
	// 必须将循环递归的结果存储在一个变量里,否则到最后一个值时,会往数组内添加该值,并返回最后一个值
	subMax := maxChild(a[:])
	if biggest > subMax {
		return biggest
	}
	return subMax
}
func main() {
	var a = [...]int {4,5,9,20,2,5,60,3,90,1}
	fmt.Println(maxChild(a[:]))
}

对数组进行快速排序

js实现

function quickSort (arr) {
  if (arr.length < 2) return arr;
  const pivot = arr[0];
  const less = [];
  const greater = [];
  for (let i = 1; i < arr.length; i++) {
    if (arr[i] <= pivot) less.push(arr[i]);
    else greater.push(arr[i])
  }
  return [...quickSort(less), pivot, ...quickSort(greater)];
}
console.log(quickSort([10, 6, 1, 23, 2, 4]))

快速排序的运行时间为O(nlogn)

对数组进行插入排序

function insertSort (list) {
  const length = list.length;
  for (let j = 1; j < length; j++) {
    const key = list[j];
    let i = j - 1;
    while (i >= 0 && list[i] > key) {
      list[i+1] = list[i]
      i = i - 1
    }
    list[i+1] = key
  }
  return list
}
console.log(insertSort([5,6,1,2,4,3,7,10,9,12]))

插入排序的运行时间为O(n²)

傅里叶FT

傅里叶变换则可以让微分和积分在频域中变为乘法和除法,大学数学瞬间变小学算术有没有

Divide-and-Conquer(分治策略)

用分治策略求解数组中和最大的子数组,犹如买股票,确定哪段时间股票涨值价格最高。

const list = [13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7]
function findMaxCrossingSubarray(list, low, mid, high) {
  let leftSum = Number.NEGATIVE_INFINITY;
  var sum = 0;
  let maxLeft;
  for (let i = mid; i >= low; i--) { //这里必须递减,若递增的话,得出的结果是错误的
    sum = sum + list[i];
    if (sum > leftSum) {
      leftSum = sum;
      maxLeft = i;
    }
  }
  let rightSum = Number.NEGATIVE_INFINITY;
  sum = 0;
  let maxRight;
  for (let j = mid + 1; j <=high; j++) {
    sum = sum + list[j];
    if (sum > rightSum) {
      rightSum = sum;
      maxRight = j
    }
  }
  return [maxLeft, maxRight, leftSum + rightSum];
}
function findMaxSubarray(list, low, high) {
    if (high == low) return [low, high, list[low]];
    let mid = Math.floor((low + high) / 2);
    let [leftLow, leftHigh, leftSum] = findMaxSubarray(list, low, mid);
    let [rightLow, rightHigh, rightSum] = findMaxSubarray(list, mid + 1, high);
    let [crossLow, crossHigh, crossSum] = findMaxCrossingSubarray(list, low, mid, high);
    
    console.log('leftSum: ' + leftSum);
    console.log('rightSum: ' + rightSum);
    console.log('crossSum: ' + crossSum);
    if (leftSum >= rightSum && leftSum >= crossSum) {
      return [leftLow, leftHigh, leftSum];
    } else if (rightSum >= leftSum && rightSum >= crossSum) {
      return [rightLow, rightHigh, rightSum]
    } else {
      return [crossLow, crossHigh, crossSum];
    }
}
console.log(findMaxSubarray(list, 0, list.length-1))

成功打印出[7, 10, 43],跨越中间值求解时,必须呈递减操作,否则无法得出最大数组和值

矩阵

1929年,希尔(Hill)通过矩阵理论对传输信息进行加密处理,提出了在密码学史上有重要地位的希尔加密算法。
在这里插入图片描述

堆排序

最大堆排序

function max_heapify(A, i, size) {
      let left = 2*i + 1;
      let right = 2*i +2;
      let maxIndex = i;
      if (left < size && A[maxIndex] > A[left]) {
        maxIndex = left;
      }
      if (right < size && A[maxIndex] > A[right]) {
        maxIndex = right;
      }
      if (maxIndex != i) {
        let temp = A[maxIndex];
        A[maxIndex] = A[i]
        A[i] = temp;
        max_heapify(A, maxIndex, size);
      }
    }

    function buildHeap(A, size) {
      const start = parseInt(size/2);
      for (let i=start; i>-1; i--) {
        max_heapify(A, i, size)
      }
    }
    function heapSorting(A) {
      const size = A.length;
      buildHeap(A, size);
      for (let i = size-1; i>0; i--) {
        let temp = A[i];
        A[i] = A[0];
        A[0] = temp;
        max_heapify(A, 0, i);
      }
      return A;
    }
    arr = [1,4,2,16,10,14,8,3,9,7];
    console.log(heapSorting(arr)) // [16, 14, 10, 9, 8, 7, 4, 3, 2, 1]

最小堆排序算法亦可推算出

堆排序的另一种算法,亦是书中伪代码的实现

function max_heapify(A, i, size) {
  let l = 2*i;
  let r = 2*i + 1;
  let largest;
  if (l < size && A[l] > A[i]) {
    largest = l;
  } else {
    largest = i;
  }
  if (r < size && A[r] > A[largest]) {
    largest = r;
  }
  if (largest != i) {
    let temp = A[i];
    A[i] = A[largest];
    A[largest] = temp;
    max_heapify(A, largest, size)
  }
}

有问题TODO: 从堆中抽取最大数字,并将其从堆中删掉,伪代码实现

function heap_extract_max(A, size) {
  if (size < 1) throw Error('heap underflow')
  let max = A[0];
  A[0] = A[size - 1];
  size--;
  A.shift();
  max_heapify(A, 0, size);
  console.log(A)
  return max;
}
arr = [1,2,7,5,9,3];
console.log(heap_extract_max(arr, 6))

函数递归调用: return之后会继续执行递归,最里面一层的方法return,便会回到调用它的上一层,然后再一层一层这样递归回去直到最开始调用的方法return才会结束递归

红黑树

  1. 节点是红色或黑色
  2. 根节点是黑色
  3. 每个叶子节点都是黑色的空节点(NIL节点)
  4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
  5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

左旋转

逆时针选择红黑树的两个节点,使得父节点被自己的右孩子取代,而自己成为自己的左孩子

右旋转

顺时针旋转红黑树的两个节点,使得父节点被自己的左孩子取代,而自己成为自己的右孩子。

贝叶斯

所谓"条件概率"(Conditional probability),就是指在事件B发生的情况下,事件A发生的概率,用P(A|B)来表示

已知某种疾病的发病率是0.001,即1000人中会有1个人得病。现有一种试剂可以检验患者是否得病,它的准确率是0.99,即在患者确实得病的情况下,它有99%的可能呈现阳性。它的误报率是5%,即在患者没有得病的情况下,它有5%的可能呈现阳性。现有一个病人的检验结果为阳性,请问他确实得病的可能性有多大?

详情

平衡二叉树

Go的实现方法

package main
import (
    "fmt"
)
var NULL = -1 << 63
type TreeNode struct {
	Val int
	Left *TreeNode
	Right *TreeNode
}
// Ints2TreeNode 利用 []int 生成 *TreeNode
func Ints2TreeNode(ints []int) *TreeNode {
	n := len(ints)
	if n == 0 {
		return nil
	}

	root := &TreeNode{
		Val: ints[0],
	}

	queue := make([]*TreeNode, 1, n*2)
	queue[0] = root

	i := 1
	for i < n {
		node := queue[0]
		queue = queue[1:]

		if i < n && ints[i] != NULL {
			node.Left = &TreeNode{Val: ints[i]}
			queue = append(queue, node.Left)
		}
		i++

		if i < n && ints[i] != NULL {
			node.Right = &TreeNode{Val: ints[i]}
			queue = append(queue, node.Right)
		}
		i++
	}

	return root
}

func isBalanced(root *TreeNode) bool {
    if root == nil {
        return true
    }
    return abs(height(root.Left) - height(root.Right)) <= 1 && isBalanced(root.Left) && isBalanced(root.Right)
}

func height(root *TreeNode) int {
    if root == nil {
        return 0
    }
    return max(height(root.Left), height(root.Right)) + 1
}

func max(x, y int) int {
    if x > y {
        return x
    }
    return y
}

func abs(x int) int {
    if x < 0 {
        return -1 * x
    }
    return x
}
func main() {
	treeNodes := Ints2TreeNode([]int{3,9,20,12,8,15,7})
	fmt.Println(isBalanced(treeNodes))
}


希尔排序

function shellSort(arr) {
  let gap = 1;
  while (gap < arr.length) {
    gap = gap * 3 + 1;
  }
  while (gap > 0) {
    for (let i = gap, len = arr.length; i < len; i++) {
      let tmp = arr[i];
      let j = i - gap;
      while (j >= 0 && arr[j] > tmp) {
        arr[j+gap] = arr[j];
        j -= gap;
      }
      arr[j+gap] = tmp;          
    }
    gap = Math.floor(gap/3);
  }
  return arr;
}
console.log(shellSort([2,5,4,1,3,9,7,10,20,13,19,14]))

两数之和

halfrost的解题思路

func twoSum(nums []int, target int) []int {
	m := make(map[int]int)
	for k, v := range nums {
		if idx, ok := m[target-v]; ok {
			return []int{idx, k}
		}
		m[v] = k
	}
	return nil
}

我的思路,很笨

func twoSum(nums []int, target int) []int {
    k := len(nums) - 1;
    Loop:
    for i := 0; i <= k; i++ {
        for j := i+1; j <= k; j++ {
            sum := nums[i] + nums[j];
            if (sum == target) {
                return []int{i, j}
                break Loop
            }
        }
    }
    return nil
}

Add Two Numbers

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

go思路

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.
package leetcode

import (
	"github.com/halfrost/LeetCode-Go/structures"
)

// ListNode define
type ListNode = structures.ListNode

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */

func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
	if l1 == nil || l2 == nil {
		return nil
	}
	head := &ListNode{Val: 0, Next: nil}
	current := head
	carry := 0
	for l1 != nil || l2 != nil {
		var x, y int
		if l1 == nil {
			x = 0
		} else {
			x = l1.Val
		}
		if l2 == nil {
			y = 0
		} else {
			y = l2.Val
		}
		current.Next = &ListNode{Val: (x + y + carry) % 10, Next: nil}
		current = current.Next
		carry = (x + y + carry) / 10
		if l1 != nil {
			l1 = l1.Next
		}
		if l2 != nil {
			l2 = l2.Next
		}
	}
	if carry > 0 {
		current.Next = &ListNode{Val: carry % 10, Next: nil}
	}
	return head.Next
}

JS思路

        function Ints2List(arr) {
            if (!arr.length) return null;
            let l = new ListNode([])
            let t = l
            arr.forEach(v => {
                t.next = new ListNode(v);
                t = t.next
            });
            return l.next;
        }
        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 addTwoNumbers = function (l1, l2) {
            if (l1 === null || l2 === null) return null;
            let head = new ListNode(0, null);
            let current = head;
            let carry = 0;
            while (l1 !== null || l2 !== null) {
                let x, y;
                if (l1 === null) {
                    x = 0
                } else {
                    x = l1.val
                }
                if (l2 === null) {
                    y = 0
                } else {
                    y = l2.val
                }
                current.next = new ListNode((x + y + carry) % 10, null);
                current = current.next;
                carry = Math.floor((x + y + carry) / 10);
                if (l1 !== null) l1 = l1.next;
                if (l2 !== null) l2 = l2.next;
            }
            if (carry > 0) current.next = new ListNode(carry % 10, null);
            return head.next
        };
        const param1 = Ints2List([2, 4, 3]);
        console.log(param1);
        const param2 = Ints2List([5, 6, 4]);
        console.log(param2);
        console.log(addTwoNumbers(param1, param2));

Longest Common Prefix

Write a function to find the longest common prefix string amongst an array of strings.

If there is no common prefix, return an empty string “”.

JS思路

/**
 * @param {string[]} strs
 * @return {string}
 */
 var longestCommonPrefix = function(strs) {
    let longestPrefix = '';
    if (strs.length > 0) {
      longestPrefix = strs[0];
      for (let i = 1; i < strs.length; i++) {
        for (let j = 0; j < longestPrefix.length; j++) {
          if (strs[i][j] != longestPrefix[j]) {
            longestPrefix = longestPrefix.slice(0, j);
            break;
          }
        }
      }
    }

    return longestPrefix;
};

Remove Duplicates from Sorted Array

Example 1:

Given nums = [1,1,2],

Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.

It doesn't matter what you leave beyond the returned length.

JS

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    let len = nums.length;
    if (len === 0) return 0;
    let targetIndex = 1;
    let first = nums[0];
    let i;
    for (i = 1; i < len; i++) {
      if (nums[i] !== first) {
        first = nums[i];
        nums[targetIndex] = nums[i];
        targetIndex++;
      }
    }
    return targetIndex;
};

GO

func removeDuplicates(nums []int) int {
    if len(nums) == 0 {
        return 0
    }
    targetIndex := 1;
    first := nums[0]
    for i, val := range nums {
        if val != first {
            first = val
            nums[targetIndex] = nums[i]
            targetIndex++
        }
    }
    return targetIndex
}

Longest Substring Without Repeating Characters

Input: "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3. 
             Note that the answer must be a substring, "pwke" is a subsequence and not a substring.

JS

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
  let len = s.length;
  let set = new Set();
  let res = 0, i = 0, j = 0;
  while (i < len && j < len) {
    if (!set.has(s.charAt(j))) {
      set.add(s.charAt(j++));
      res = Math.max(res, j - i);
    } else {
      set.delete(s.charAt(i++));
    }
  }
  return res
};

GO 有问题TODO

func lengthOfLongestSubstring(s string) int {
    l := len(s)
    m := make(map[string]int)
    res, i, j := 0
    for i < len && j < len {
        if n, ok := m[s.charAt(j++)]{
            delete(m, s.charAt(i++)) 
        } else {
            m[s.charAt(j++)] = n
            if j-i > res{
                res = j-i
            }
        }
    }
    return res
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值