文章目录
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才会结束递归
红黑树
- 节点是红色或黑色
- 根节点是黑色
- 每个叶子节点都是黑色的空节点(NIL节点)
- 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
- 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
左旋转
逆时针选择红黑树的两个节点,使得父节点被自己的右孩子取代,而自己成为自己的左孩子
右旋转
顺时针旋转红黑树的两个节点,使得父节点被自己的左孩子取代,而自己成为自己的右孩子。
贝叶斯
所谓"条件概率"(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
}