leetcode
9. sqrt() 向下取整后的整数 输入:8 = 2.82 输出: 2
var mySqrt = function(x) {
//暴力解法
if(x <= 1)return x;
//parseInt(x / 2) + 2 一个1是取整后的值 一个1是遍历足够次数
for(let i = 1; i < parseInt(x / 2) + 2; i++){
//暴力访问每个值的平方
if(i * i > x) return i - 1;
}
};
console.log(mySqrt(2));
var mySqrtI = function(x) {
//二分法
//考虑0
if(x <= 0){
return 0;
}
//left为1考虑n为1的情况
let left = 1, right = x, mid;
while(left + 1 < right){
mid = parseInt((left + right) / 2);
if(mid * mid === x) return mid;
if(x > mid * mid) left = mid;
else right = mid;
}
return left;
};
console.log(mySqrtI(8));
72. 动态规划 最短编辑距离
/**
* @param {string} word1
* @param {string} word2
* @return {number}
*/
//动态规划
var minDistance = function(word1, word2) {
let dp = [];
dp[0] = [];
//初始化dp[i,j]word1中第i个匹配Word2中第j个的最短编辑距离
for(let j = 0; j <= word2.length; j++){
dp[0][j] = j;
}
for(let i = 0; i <= word1.length; i++){
if(dp[i]){
dp[i][0] = i;
}else{
dp[i] = [];
dp[i][0] = i;
}
}
//动态规划
for(let k = 1; k <= word1.length; k++){
for(let h = 1; h <= word2.length; h++){
if(word1[k - 1] === word2[h - 1]){
dp[k][h] = dp[k - 1][h - 1];
}else{
let a = dp[k - 1][h] + 1;
let b = dp[k][h - 1] + 1;
let c = dp[k - 1][h - 1] + 1;
dp[k][h] = Math.min(a, b, c);
}
}
}
return dp[word1.length][word2.length];
};
//递归
var minDistance = function(word1, word2) {
return minDistanceHelper(word1, word2, word1.length, word2.length);
};
function minDistanceHelper(word1, word2, i, j){
if(i === 0) return j; //添加
if(j === 0) return i; //删除
if(word1[i - 1] === word2[j - 1]){
return minDistanceHelper(word1, word2, i - 1, j - 1);
}else{
let a = minDistanceHelper(word1, word2, i - 1, j) + 1;//删
let b = minDistanceHelper(word1, word2, i, j - 1) + 1;//增
let c = minDistanceHelper(word1, word2, i - 1, j - 1) + 1;//改
return Math.min(a, b, c);
}
}
73. 动态规划 编辑距离为1 //双指针考虑边界范围
//判断编辑距离为1
function editDistace(word1, word2){
let distance = word1.length - word2.length;
if(Math.abs(distance) > 1){
return false;
}
let i = 0, j = 0, isEdit = false;
while(i < word1.length && j < word2.length){
if(word1[i] === word2[j]){
i++;
j++;
}else{
if(isEdit){
return false;
}else if(distance === 1){
//删除
i++;
}else if(distance === -1){
//增加
j++;
}else{
//修改
i++;
j++;
}
isEdit = true;
}
}
if(i < word1.length){
return !isEdit
}
if(j < word2.length){
return !isEdit
}
return i === word1.length && j === word2.length && isEdit;
}
908. 给定一个整数数组 A,对于每个整数 A[i],我们可以选择任意 x 满足 -K <= x <= K,并将 x 加到 A[i] 中。
在此过程之后,我们得到一些数组 B。 返回 B 的最大值和 B 的最小值之间可能存在的最小差值。
var smallestRangeI = function(A, K) {
let max = A[0],min= A[0] ;
for(let i = 1; i < A.length; i++){
if(A[i] > max){
max = A[i];
}
if(A[i] < min){
min = A[i];
}
}
//重叠值则为0
return Math.max(max - min - 2 * K , 0);
};
console.log(smallestRangeI([1,3,6], 3)); //3
910. 给定一个整数数组 A,对于每个整数 A[i],我们可以选择 x = -K 或是 x = K,并将 x 加到 A[i] 中。
在此过程之后,我们得到一些数组 B。 返回 B 的最大值和 B 的最小值之间可能存在的最小差值。
var smallestRangeII = function(A, K) {
A.sort(function(x, y){
return x - y;
});
let res = A[A.length -1] - A[0];
for(let i = 0; i < A.length - 1; i++){
//贪心算法,每个值都有+k -k 除max,min外 比最大值小,则加运算不会改变结果, 比最小值大,-k不会对结果造成影响
//同时-k 相当于A[i]上+2 *k或者不变,进行问题转换
let max = Math.max(A[A.length - 1], A[i] + 2 * K) ;
let min = Math.min(A[0] + 2 * K, A[i + 1]);
res = Math.min(res, max - min);
}
return res;
};
console.log(smallestRangeII([1,3,6],3));
//法2 贪心算法 从某个pos总是之前+k 之后-k
function smallRange(A, k){
A.sort(function(a , b){
return a - b;
});
let len = A.length;
let res = A[len - 1] - A[0];
let temp = res, resArr = [];
for(let i = 0; i < len - 1; i++){
let max = Math.max(A[len - 1] - k, A[i] + k);
let min = Math.min(A[0] + k , A[i + 1] - k);
res = Math.min(res, max - min);
}
for(let j = 0; j < len - 1; j++){
let max = Math.max(A[len - 1] - k, A[j] + k);
let min = Math.min(A[0] + k , A[j + 1] - k);
temp = Math.min(temp, max - min);
if(temp === res){
let str = [];
for(let m = 0; m <= j; m++){
str[m] = A[m] + k;
}
for(let m = j + 1; m < len; m++){
str[m] = A[m] - k;
}
resArr.push(str);
}
}
return resArr;
}
console.log(smallRange([1,3,6],3)); // 3
剑指offer66题
1. 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数?(二维数组中的查找)
- 暴力解题法(O(n^2))
function Find(target, array)
{
//利用js内库实现暴力解题
for(let value of array){
if(value.includes(target)){
return true;
}
}
return false;
}
- 二分查找优化二重遍历(O(nlogn)
function Find(target, array)
{
//利用二分查找
let col = array[0].length - 1;
let row = array.length - 1;
if(row === 0 || col === 0){
return false;
}
if(target < array[0][0] || target > array[row][col]){
return false;
}
for(let value of array){
let left = 0;
let right = col;
while(left <= right){
let mid = parseInt((left + right) / 2);
if(target > value[mid]){
left = ++mid;
}else if(target < value[mid]){
right = --mid;
}else{
return true;
}
}
}
return false;
}
- 通过左下角或者右上角边界点优化(O(n))
function Find(target, array)
{
//利用左上角或者右上角边界
let col = array[0].length - 1;
let row = array.length - 1;
if(row === 0 || col === 0){
return false;
}
if(target < array[0][0] || target > array[row][col]){
return false;
}
let i = 0, j = col;
while(i <= row && j >= 0){
if(target > array[i][j]){
i++;
}else if(target < array[i][j]){
j--;
}else{
return true;
}
}
return false;
}
2.请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。(替换空格)
- 利用js内的正则表达式 => 有多少空格就需要匹配多少次
function replaceSpace(str)
{
let reg =/\s/g;
return str.replace(reg,'%20');
}
- 通过后移插入法实现字符串替代
function replaceSpace(str)
{
//在源字符串中替换
if(str.length === 0 || !str){
return str;
}
var spaceNum = 0;
for(var value of str){
if(value === ' '){
spaceNum++;
}
}
if(spaceNum === 0){
return str;
}
//新数组长度
var newStrLen = str.length + 2*spaceNum - 1;
//str长度
var oldStrLen = str.length - 1;
var newStr = Array(newStrLen);
while(oldStrLen >= 0 ){
if(str.charAt(oldStrLen) !== ' '){
newStr[newStrLen--] = str.charAt(oldStrLen--);
}else{
oldStrLen--;
newStr[newStrLen--] ='0';
newStr[newStrLen--] ='2';
newStr[newStrLen--] ='%';
}
} //申请空间
return newStr.join('');
}
3. 依次替换
function replaceStrII(str){
let strArr = str.split("");
let res = "";
for(let val of strArr){
if(val === ' '){
res += '%20';
}else{
res += val;
}
}
return res;
}
- 输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
/*function ListNode(x){
this.val = x;
this.next = null;
}*/
//1.递归 后进先出,通过全局变量保存值
function printListFromTailToHead(head)
{
// write code here
let res = []
if(!head) return res;
res = printListFromTailToHead(head.next);
res.push(head.data)
return res;
}
//2. 数组unshift方法
/*function printListFromTailToHead(head)
{
// write code here
if(!head) return [];
var node = null,res = [],temp;
while(head){
res.unshift(head.val);
head = head.next;
}
return res;
}*/
//3.头插法遍历
/*function printListFromTailToHead(head)
{
// write code here
if(!head) return [];
let temp,node = null;
let arr = [];
while(head){
temp = head.next;
head.next = node;
node = head;
head = temp;
}
while(node){
arr.push(node.val);
node = node.next;
}
return arr;
}*/
4. 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
function reConstructBinaryTree(pre, vin)
{
// write code here
let tree, index, vinLeft,vinRight;
if(!pre.length) return null;
index = vin.indexOf(pre[0]);
vinLeft = vin.slice(0, index);
vinRight = vin.slice(index + 1);
tree = new TreeNode(pre[0]);
tree.left = createTree(pre.slice(1,vinLeft.length + 1), vinLeft);
tree.right = createTree(pre.slice(pre.length - vinRight.length),vinRight);
return tree;
}
- 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
let stack1 = [], stack2 = [];
function push(node)
{
// write code here
stack1.push(node);
}
function pop()
{
if(!stack2.length){
while(stack1.length){
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
- 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
//二分法 利用旋转后的值的两部分进行比较 总有第一个部分的第一个值大于旋转后的第二部分
function minNumberInRotateArray(rotateArray)
{
// write code here
if(!rotateArray.length) return 0;
let l = 0, r = rotateArray.length;
while(l < r){ //l < r是用的length属性 比如 3 只会进入一次 4则会进入2次
if(rotateArray[l] < rotateArray[r]){ //没有旋转
return rotateArray[l];
}
let mid = parseInt((l + r) / 2);
if(rotateArray[mid] > rotateArray[mid + 1]){ //比后一个数的大小
return rotateArray[mid + 1];
}
if(rotateArray[mid - 1] > rotateArray[mid]){ //比前一个数的大小
return rotateArray[mid];
}
if(rotateArray[mid] > rotateArray[0]){
l = mid + 1;
}else{
r = mid - 1;
}
}
}
//O(n) 前一个数比后一个数大
function minNumberInRotateArray(rotateArray)
{
// write code here
if(!rotateArray.length) return 0;
let temp = rotateArray[0];
for(let i = 1; i < rotateArray.length; i++){
if(temp <= rotateArray[i]){
temp = rotateArray[i];
}else{
return rotateArray[i];
}
}
}
- 斐波那契数列
//递归
function Fibonacci(n)
{
if(n === 0) return 0;
if(n <= 2) return 1;
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
//迭代
function Fibonacci(n)
{
if(n === 0) return 0;
if(n <= 2) return 1;
let first = second = 1,sum = 0, i = 2;
while(i < n){
sum = first + second;
first = second;
second = sum;
i++;
}
return sum;
}
- 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法
//递归 n- 1 n - 2次等价于前一梯的长度加前2梯的长度
function jumpFloor(number)
{
// write code here
if(number === 1) return 1;
if(number === 2) return 2;
return jumpFloor(number - 1) + jumpFloor(number - 2);
}
//迭代
function jumpFloor(number)
{
// write code here
if(number === 1) return 1;
if(number === 2) return 2;
let start = 2, first = 1, second = 2,sum = 0;
while(start < number){
sum = first + second;
first = second;
second = sum;
start++;
}
return sum;
}
//利用全局变量的形式,递归至阶梯数为0
function jumpFloorI(number)
{
let count = [0];
jump(number, count);
return count[0];
}
function jump(number,count){
if(number === 0) {return count[0]++}
if(number >= 1) jump(number - 1,count);
if(number >= 2) jump(number - 2,count);
}
- 变态跳台阶
//易知 f(n)=f(n-1)+f(n-2)+……f(1) f(n-1)=f(n-2)+……f(1) 两式相减得f(n)=2f(n-1)
function jumpFloorII(number)
{
// write code here
//return Math.pow(2, number - 1);
let n = 1;
for(let i = 1; i < number;i++){
n = 2 * n;
}
return n;
}
//利用全局变量 至阶梯数为0为止
function jumpFloorII(number)
{
// write code here
let count = [0];
jump(number, count);
return count[0];
}
function jump(number,count){
if(number === 0) return count[0]++;
for(let i =1 ; i <= number; i++){
jump(number - i, count);
}
}
- 矩形覆盖
function rectCover(number)
{
//找规律 对数据进行找规律 图形找规律实现递归不等式
if(number <= 2) return number;
return rectCover(number - 1) + rectCover(number - 2);
}
- 幂运算
function Power(base, exponent)
{
//幂运算 考虑底数和指数的边界条件 以及为负数的情况
if(base === 0){
return exponent < 0 ? false : 0;
}
if(!exponent){
return 1;
}
let exp = Math.abs(exponent);
let res = 1;
while(exp){
res = res * base;
exp--;
}
return exponent > 0 ? res : 1 / res;
}
- 所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
//偶数向最后插入,数组向前移动
function reOrderArray(array)
{
//插入排序 + 快排的思想
let i = 0;
while(i < array.length){
if(array[i] % 2 === 0){
let j = k = i;
while(array[j] % 2 === 0){
if(j === array.length - 1) return array;
j++;
}
let temp = array[j];
while(j > k){
array[j] = array[j - 1];
j--;
}
array[j] = temp;
}
i++;
}
return array;
}
//偶数向最后插入,数组向前移动
function reOrderArray(array)
{
//将偶数放入数组末尾
let move = i = 0;
while(move + i !== array.length){
if(array[i] % 2 === 0) {
let k = i, j = array.length - 1;
let temp = array[i];
while(k < j){
array[k] = array[k + 1];
k++;
}
array[j] = temp;
move++;
}else{
i++;
}
}
return array;
}
console.log(reOrderArray([1,2,3,4,5,6,7]));
- 倒数第k个节点
//双向指针移动 使之间隔为k至第一个指针为null时停止移动
function FindKthToTail(head, k)
{
let p = head, q = head, count = 0;
while(p){
p = p.next;
count++;
if(count > k) q = q.next;
}
if(k > count) return null;
return q;
}
//一次遍历链表找到倒数第K个节点
/*function FindKthToTail(head, k)
{
let res = [];
while(head){
res.push(head);
head = head.next;
}
return k > res.length ? null : res[res.length - k];
}*/
- 合并增序链表
//归并+头结点+尾插法
function Merge(pHead1, pHead2)
{
// write code here
let p = pHead1, q = pHead2, head = res = new ListNode(0);
while(p && q){
if(p.val > q.val){
res.next = q;
res = q;
q = q.next;
}else{
res.next = p;
res = p;
p = p.next;
}
}
if(!p){
res.next = q;
}
if(!q){
res.next = p;
}
return head.next;
}
- 树的子结构
function HasSubtree(pRoot1, pRoot2)
{
// write code here
if(!pRoot1 || !pRoot2) return false;
//遍历大树看是否有相同的子结构
return jugeTree(pRoot1, pRoot2) || HasSubtree(pRoot1.left, pRoot2) || HasSubtree(pRoot1.right, pRoot2);
}
//判断两棵树是否相同
function jugeTree(tree1, tree2){
if(!tree2){
return true;
}
if(!tree1){
return false;
}
if(tree1.val !== tree2.val){
return false;
}
return jugeTree(tree1.left, tree2.left) && jugeTree(tree1.right,tree2.right);
}
- 交换左右子树
//交换左右子树
function Mirror(root)
{
if(root){
if(!root.left && !root.right) return;
let temp = root.left;
root.left = root.right;
root.right = temp;
Mirror(root.left);
Mirror(root.right);
}
return root;
}
16.顺时针打印举证
//循环边界条件 检查循环退出时值的正确情况则可知晓
function printMatrix(matrix)
{
//利用4个标志位判断是否打印完成本题技巧性较强
let up = 0; down = matrix.length - 1, left = 0, right = matrix[0].length - 1;
let res = [],row , col;
while(true){
//从左至右打印
for(col = left; col <= right; col++){
res.push(matrix[up][col]);
}
up++;
//如果up >= down 则为打印up = down的情况 故为up > down
if(up > down){
break;
}
//从上到下打印
for(row = up; row <= down; row++){
res.push(matrix[row][right])
}
right--;
if(left > right){
break;
}
//从右至左打印
for(col = right; col >= left; col--){
res.push(matrix[down][col]);
}
down--;
//上下重叠
if(up > down){
break;
}
//从下至上打印
for(row = down; row >= up; row--){
res.push(matrix[row][left]);
}
left++;
//左右重叠
if(left > right){
break;
}
}
return res;
}
- 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数
//法一辅助栈压入最小值 弹栈时当辅助栈最小值=== 弹栈值 最小值出栈
function push(node) {
stack1.push(node);
if (stack2.length === 0) {
stack2.push(node);
} else if (node < stack2[stack2.length - 1]) {
stack2.push(node);
}
return stack1.length;
}
function pop() {
let node = stack1.pop();
if (node === stack2[stack2.length - 1]) {
stack2.pop();
}
return node;
}
function top() {
return stack1[stack1.length - 1];
}
function min() {
return stack2[stack2.length - 1];
}
var stack1 = [];
var stack2 = [];
//法二 辅助栈保存每个元素的最小值 压栈值 < 辅助栈最小值 辅助栈压入压栈值 否则压入辅助栈前一个最小值 弹栈时则可同时弹栈
function push(node) {
stack1.push(node);
if (stack2.length === 0) {
stack2.push(node);
} else if (node < stack2[stack2.length - 1]) {
stack2.push(node);
} else {
stack2.push(stack2[stack2.length - 1]);
}
return stack1.length;
}
function pop() {
stack2.pop();
return stack1.pop();
}
function top() {
return stack1[stack1.length - 1];
}
function min() {
return stack2[stack2.length - 1];
}
var stack1 = [];
var stack2 = [];
- 出入栈顺序
//类似括号匹配
function IsPopOrder(pushV, popV)
{
// write code here
let res = [], j = 0;
for(let i = 0; i < pushV.length; i++){
res.push(pushV[i]);
while(res.length !== 0 && popV[j] === res[res.length - 1]){
res.pop();
j++;
}
}
return !res.length;
}
- 层次遍历
//判断树是否为空 注意写二叉树的时候
function PrintFromTopToBottom(root) {
// write code here
if (!root) return [];
let queue = [root],
res = [];
while (queue.length) {
let node = queue.shift();
res.push(node.val);
if (node.left) queue.push(node.left);
if (node.right) queue.push(node.right);
}
return res;
}
- 后序bst
function VerifySquenceOfBST(sequence)
{
if(!sequence.length) return false;
return isBST(sequence, 0, sequence.length - 1);
}
//判断是否为二叉搜索树 左边值 < 根值 < 右边值
function isBST(arr,start,end){
if(start >= end){ //递归至只有一个节点则返回
return true;
}
let rootVal = arr[end], split = start;
while(split < end && arr[split] < rootVal){ // 左边的值比根小
split++;
}
//右边值比根大
let i = split;
while(i < end){
if(arr[i] < rootVal){
return false;
}
i++;
}
return isBST(arr, start, split - 1) && isBST(arr, split, end - 1);
}
function FindPath(root, expectNumber)
{
if(!root) return [];
let res = [];
treePath(root, expectNumber, res, []);
return res.sort(function(a,b){return b.length - a.length});
}
//二叉树遍历二叉树退出节点 为空时退出,满足相应条件执行相应操作即可
function treePath(root, target, res, temp){
if(root){
target -= root.val;
temp.push(root.val);
if(target === 0 && !root.left && !root.right){
res.push(temp.slice());
}
treePath(root.left, target, res, temp);
treePath(root.right, target, res, temp);
temp.pop();
}
}
- 复制链表
//通过映射关系找到对应的random next值
function Clone(pHead)
{
if(!pHead){
return null;
}
//头节点也要设置新旧节点的对应位置
let p = pHead, res = q = new RandomListNode(pHead.label);
let nodeMap = new Map();
nodeMap.set(pHead, q);
while(p){
//next不存在则重新申请节点
if(p.next && nodeMap.has(p.next)){
q.next = nodeMap.get(p.next);
}else if(p.next){
let temp = new RandomListNode(p.next.label);
nodeMap.set(p.next, temp);
q.next = temp;
}
//random不在则也重新申请节点
if(p.random && nodeMap.has(p.ramdom)){
q.random = nodeMap.get(p.ramdom);
}else if(p.random){
let temp = new RandomListNode(p.random.label);
nodeMap.set(p.random, temp);
q.random = temp;
}
//遍历每一个节点 给节点的next 和 random赋值
p = p.next;
q = q.next;
}
return res;
}
//通过映射关系找到对应的random next值
function Clone(pHead)
{
if(!pHead){
return null;
}
let p = node = pHead, q;
while(p){
q = new RandomListNode(p.label);
//先用后改插入法
let temp = p.next;
q.next = temp;
p.next = q;
p = temp;
}
//修改random节点
while(node.next.next){
if(node.random){
//复制节点的下一个节点random 为random节点的下一个
node.next.random = node.random.next;
}
node = node.next.next;
}
//获取偶数节点链成链表
let res = pHead.next;
while(pHead.next.next){
let temp = pHead.next.next;//保存奇数个节点即源节点
pHead.next.next = pHead.next.next.next;//修改指针
pHead = temp;
}
return res;
}
//暴力解法 每次都要去找random 此时应试图找到一种映射关系直接获取ramdom值
function Clone(pHead)
{
if(!pHead){
return null;
}
let resList = res = new RandomListNode(0);
let head = pHead;
while(head){
let node = new RandomListNode(head.label);
res.next = node;
res = node;
head = head.next;
}
let list = resList.next;
while(pHead){
let temp = pHead;
let listTemp = list;
while(pHead.random){
if(pHead.random === temp){
break;
}
listTemp = listTemp.next;
temp = temp.next;
}
list.random = listTemp;
list = list.next;
pHead = pHead.next;
}
return resList.next;
}
- 搜索二叉树变成双向链表
//递归找到当前节点和当前节点的前一个节点修改指针
function Convert(pRootOfTree)
{
if(!pRootOfTree) return null;
let pre = [null];
convertHelper(pRootOfTree, pre);
//回到头节点
while(pRootOfTree.left){
pRootOfTree = pRootOfTree.left;
}
return pRootOfTree;
}
//pre为地址任何时候保存同一值 否则pre值将不会是前一个值
function convertHelper(root, pre){
if(root){
convertHelper(root.left, pre);
//进行当前节点和前一个节点的转换
root.left = pre[0];
if(pre[0]) pre[0].right = root;
pre[0] = root;
convertHelper(root.right, pre);
}
}
//迭代保存当前节点的前一个节点 中序情况下
function Convert(pRootOfTree)
{
if(!pRootOfTree) return null;
let pre = null, stack = [], p = pRootOfTree;
//栈不空 节点不空都可以进入
while(p || stack.length){
//一直进入左子树
while(p){
stack.push(p);
p = p.left;
}
let curr = stack.pop();
//进行交换操作
curr.left = pre;
if(pre) pre.right = curr;
pre = curr;
//访问右子树
p = curr.right;
}
while(pRootOfTree.left){
pRootOfTree = pRootOfTree.left;
}
return pRootOfTree;
}
- 字符串全排列
function Permutation(str)
{
//全排列:第一个数后之后的数相交换 依次递归 重复值的全排列:交换时为相同值则不交换
if(str === '') return [];
let res = [];
permutationHelper(str.split(""),res,0);
res.sort();
return res;
}
function permutationHelper(arr, res, i){
if(i === arr.length - 1){
if(!res.includes(arr.join(""))){ //去除重复交换的字符串
res.push(arr.join(""));
}
}else{
for(let j = i ; j < arr.length; j++){
swap(arr, i , j);
permutationHelper(arr, res, i + 1);
swap(arr, i, j); //恢复原来序列 仅和第一个数交换
}
}
}
function swap(arr, i , j ){
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
- 次数超过一半数组长度的数字(限定存在仅有一个)
//map
function MoreThanHalfNum_Solution(numbers)
{
let map = new Map();
let res = 0;
for(let val of numbers){
if(map.has(val)){
map.set(val, map.get(val) + 1);
}else{
map.set(val,1);
}
}
//回调即是闭包 注意每个api的作用,回调函数的返回值并非当前函数的返回值
map.forEach(function(count, key){
if(count > (numbers.length / 2)){
res = key;
}
})
return res;
}
console.log(MoreThanHalfNum_Solution([1,2,3,2,2,2,5,4,2]));
//简便方法: val time 寻找最后的val是否存在大于一半的次数
//如果存在该数 该数出现的次数比其他所有出现的次数和还要多
//简便方法: val time 寻找最后的val是否存在大于一半的次数
//如果存在该数 该数出现的次数比其他所有出现的次数和还要多
function MoreThanHalfNum_Solution(numbers)
{
let temp , time = 1;
for(let val of numbers){
if(val === temp){
time++;
}else{
time--;
}
if(time === 0){
temp = val;
time = 1;
}
}
let count = 0;
for(let num of numbers){
if(num === temp){
count++;
}
}
return count > (numbers.length / 2) ? temp : 0;
}
//计数排序
function MoreThanHalfNum_Solution(numbers)
{
let count = parseInt(numbers.length / 2);
let min = max = numbers[0], arr = [];
for(let val of numbers){
if(min > val){
min = val;
}
if(max < val){
max = val;
}
}
for(let i = 0; i <= max - min; i++){
arr[i] = 0;
}
for(let j = 0; j < numbers.length; j++){
arr[numbers[j] - min]++;
}
for(let m = 0; m < numbers.length; m++){
if(arr[numbers[m] - min] > count){
return numbers[m];
}
}
return 0;
}
- 最小的K个数
//快速排序去掉递归条件
function GetLeastNumbers_Solution(input, k)
{
//边界条件
if(!k || !input.length || k > input.length) return [];
let start = 0, end = input.length - 1;
let mid = quickSort(input, start, end);
while(mid !== (k - 1)){ //不存在分界线 左边的比mid小 右边的比mid大 最小可包含mid
if(mid > (k - 1)){
end = mid - 1;
mid = quickSort(input, start, end);
}else{
start = mid + 1;
mid = quickSort(input, start, end);
}
}
return input.slice(0, k).sort(function(a, b){return a - b});
}
function quickSort(arr, l , r){ //分治并未排序
let i = l, j = r, temp = arr[i];
while(i < j){
while(i < j && arr[j] > temp) j--;
if(i < j) arr[i++] = arr[j];
while(i < j && arr[i] < temp) i++;
if(i < j) arr[j--] = arr[i];
}
arr[i] = temp;
return i;
}
//冒泡排序 从后往前
function GetLeastNumbers_Solution(input, k)
{
//边界条件
if(!k && !input.length && k > input.length) return [];
for(let i = 0; i < input.length - 1; i++){
for(let j = input.length - 1; j > i; j--){
if(input[j] < input[j - 1]){
let temp = input[j];
input[j] = input[j - 1];
input[j - 1] = temp;
}
}
k--;
if(!k){
return input.slice(0, i + 1);
}
}
return input;
}
- 求连续最大和
function FindGreatestSumOfSubArray(array)
{
let max = array[0], sum = 0;
//数学问题 求最大值:为正则继续累加 为负重新计数 为负一定不可能是连续最大值
for(let i = 0; i < array.length; i++){
if(sum >= 0){
sum += array[i];
}else{
sum = array[i];
}
if(sum > max){
max = sum;
}
}
return max;
}
function FindGreatestSumOfSubArray(array)
{
let max = array[0], sum = 0, dp = [array[0]];
//动态规划 最大值:当前元素 + 之前连续序列最大值
for(let i = 1; i < array.length; i++){
sum = dp[i - 1] + array[i];
if(sum > array[i]){
dp[i] = sum; //保存当前最大值
}else{
dp[i] = array[i]; //保存当前最大值
}
if(dp[i] > max){
max = dp[i];
}
}
return max;
}
function FindGreatestSumOfSubArray(array)
{
let max = array[0], sum;
//暴力解决法 求出所有连续串的和
for(let i = 0; i < array.length; i++){
sum = 0;
for(let j = i; j < array.length; j++){
sum += array[j];
if(sum > max){
max = sum;
}
}
}
return max;
}
- 计算1的个数
//计算各位 10位 100位 ...1的个数
function NumberOf1Between1AndN_Solution(n)
{
let res = 0, a, b, time;
for(let i = 1; i <= n; i *= 10){
a = parseInt(n / i); //位
b = n % i; //余数
//temp = a % 10 === 1 ? b + 1 : 0; //判断为数是否为1 需要在加b + 1
time = parseInt((a + 8) / 10) * i + (a % 10 === 1) * (b + 1); //1的次数 等于百位前的次数*百位
res += time;
}
return res;
}
- 求组合最小值
function PrintMinNumber(numbers)
{
//冒泡排序 ASCII码最大的放最后 a + b > b + a 把大数往右放,小数往前方则是最小值
if(!numbers.length) return "";
for(let i = 0; i < numbers.length - 1; i++){
for(let j = 0; j < numbers.length - 1 - i; j++){
let a = '' + numbers[j] + numbers[j + 1];
let b = '' + numbers[j + 1] + numbers[j];
if(Number(a) > Number(b)){
swap(numbers, j , j + 1);
}
}
}
return Number(numbers.join(''));
}
function swap(arr, i, j){
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
function PrintMinNumber(numbers)
{
//暴力解法 排列后的最小值
if(!numbers.length) return "";
let res = [];
com(numbers, 0, res);
return Math.min(...res);
}
//排列得到所有可能的组合
function com(arr, i, res){
if(i === arr.length - 1){
if(!res.includes(Number(arr.join("")))){
res.push(Number(arr.join("")));
}
}else{
for(let j = i; j < arr.length ; j++){
swap(arr, i, j);
com(arr, i + 1, res);
swap(arr,i, j);
}
}
}
//交换
function swap(arr, i, j){
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
- 丑数 倍数取最小
//质因数为能被该数整除的质数 1不是质数也不是合数 质数的质因数则是本身 合数则需进行分解即分解因数
function GetUglyNumber_Solution(index)
{
if(index < 7) return index;
let res = [1], p2 = 0, p3 = 0, p5 = 0; //三个队列 用下标标识 *2 *3 *5 的队列取最小值压入丑数数组
while(res.length < index){
let min = Math.min(res[p2] * 2, res[p3] * 3, res[p5] * 5);
if(min === res[p2] * 2) p2++;
if(min === res[p3] * 3) p3++;
if(min === res[p5] * 5) p5++;
res.push(min);
}
return res[index - 1];
}
- 逆序对
//归并排序 两两有序 从尾部开始排序交换 则arr[i] > arr[j]; 则i > arr[j]前的数组 count += j - mid;
function InversePairs(data)
{
let count = inversePairsHelper(data, 0, data.length - 1);
return count;
}
//
function inversePairsHelper(arr, l, r){ //归并排序 分治法
if(l < r){
let mid = parseInt((l + r) / 2);
let leftCount = inversePairsHelper(arr, l, mid); //计算每个数后面的逆序数
let rightCount = inversePairsHelper(arr, mid + 1, r);
let count = 0, temp = [], i = mid, j = r, len = r - l;
//排序 申请空间方式
while(i >= l && j > mid){
if(arr[i] > arr[j]){
count += j - mid;
if(count >= 1000000007){
count %= 1000000007;
}
temp[len--] = arr[i--];
}else{
temp[len--] = arr[j--];
}
}
while(i >= l){ //左边太长
temp[len--] = arr[i--];
}
while(j > mid){ //右边太长
temp[len--] = arr[j--];
}
len = 0;
i = i + 1;
while(i <= r){
arr[i++] = temp[len++];
}
return (leftCount + rightCount + count) % 1000000007;
}else{
return 0;
}
}
- 求一个数有序数组中出现的次数 通过插入位置 / 或者判断最开始出现次数 结束出现次数即可
//二分法
function GetNumberOfK(data, k)
{
//找到 k + 0.5 k - 0.5 插入的位置进行相减即可
return binSearch(data, k + 0.5) - binSearch(data, k - 0.5);
}
function binSearch(arr, num){
let l = 0, r = arr.length - 1; //二分法 有等于条件
while(l <= r){
let mid = parseInt( ( r + l) /2 );
if(arr[mid] > num){
r = mid - 1;
}else{
l = mid + 1;
}
}
return l;
}
//二分法 二分法l <= r 最后一个数需要查找, 而分治递归结束只需l < r 即递归到只有一个数时则返回
function GetNumberOfK(data, k)
{
//找到 k + 0.5 k - 0.5 插入的位置进行相减即可
return binSearch(data, k) - binSearchStack(data, k, 0, data.length - 1) + 1;
}
//开始位置
function binSearchStack(arr, num, l , r){
if(l <= r){
let mid = parseInt(( l + r) / 2);
if(arr[mid] > num){
return binSearchStack(arr, num, l, mid - 1);
}else if(arr[mid] < num){
return binSearchStack(arr, num, mid + 1, r);
}else if(mid - 1 >= 0 && arr[mid - 1] === num){
return binSearchStack(arr, num, l, mid - 1);
}else{
return mid;
}
}else{
return 0; //不存在最后返回 0 不存在时返回0
}
}
//结束位置
function binSearch(arr, num){
let l = 0, r = arr.length - 1; //二分法 有等于条件
while(l <= r){
let mid = parseInt( ( r + l) /2 );
if(arr[mid] > num){
r = mid - 1;
}else if(arr[mid] < num){
l = mid + 1;
}else if(mid + 1 < arr.length && arr[mid + 1] === num){
l = mid + 1;
}else{
return mid;
}
}
return -1; //没有最后返回-1
}
- 求二叉树的高度
//返回左右两颗树高最大值
function TreeDepth(pRoot)
{
if(pRoot){
return Math.max(TreeDepth(pRoot.left), TreeDepth(pRoot.right)) + 1;
}else{
return 0 ;
}
}
//返回左右两颗树高最大值
function TreeDepth(pRoot)
{
if(pRoot){
let leftHeight = TreeDepth(pRoot.left);
let rightHeight = TreeDepth(pRoot.right);
return Math.max(leftHeight, rightHeight) + 1;
}else{
return 0 ;
}
}
- 判断平衡二叉树
//使用一个变量判断是否为平衡二叉树 只要不平衡则会一直返回-
function IsBalanced_Solution(pRoot)
{
return isBalanceTree(pRoot) === -1 ? false : true;
}
function isBalanceTree(root){
if(root){
let leftHeight = isBalanceTree(root.left);
if(leftHeight === -1){
return -1;
}
let rightHeight = isBalanceTree(root.right);
if(rightHeight === -1){
return -1;
}
if(Math.abs(leftHeight - rightHeight) > 1){
return -1;
}
return Math.max(leftHeight , rightHeight) + 1;
}else{
return 0;
}
}
//使用一个变量判断是否为平衡二叉树 只要不平衡则会一直返回-
function IsBalanced_Solution(pRoot)
{
isBalance = true;
isBalanceTree(pRoot);
return isBalance;
}
var isBalance = true;
function isBalanceTree(root){
if(root){
let leftHeight = isBalanceTree(root.left);
let rightHeight = isBalanceTree(root.right);
if(Math.abs(leftHeight - rightHeight) > 1){
isBalance = false;
}
return Math.max(leftHeight, rightHeight) + 1;
}else{
return 0;
}
}
- 求只出现一次的两个数
//异或法 将其分为两组数 每组里只有一个出现一次的数 其余出现2次
function FindNumsAppearOnce(array)
{
//相异为1 相同为0 0异或任何数为本身
if(array.length < 2) return null;
let temp = apperOnce(array); // 得到两个不同的数异或值
let bitIndex = findBitIndex(temp); // 找到第一个位为1的位下标进行分组 位为1代表两个数不同
let a = 0, b = 0;
for(let val of array){
if(isBitOne(val, bitIndex)){
a ^= val;
}else{
b ^= val;
}
}
return [a , b];
}
function findBitIndex(num){
let index = 1;
//计算位为1的下标
while( (num & 1) === 0 && index < 32){
num = num >> 1;
index++;
}
return index;
}
function isBitOne(num, index){ // 判断某个数的第几位是否为1
return (num >> (index - 1)) & 1 == 1; //>>带符号右移
}
function apperOnce(arr){
return arr.reduce((pre, curr) => pre ^ curr);
}
- 求序列和
function FindContinuousSequence(sum)
{
//双指针 确定范围
let start = 1, end = 2, res = [], total;
while(start < end){
//计算范围内的和
total = (start + end) * (end - start + 1) / 2;
if(total === sum){
let temp = [], m = start, n = end;
while(m <= n){
temp.push(m);
m++;
}
res.push(temp);
start += 1;
}else if(total < sum){
end += 1;
}else{
start += 1;
}
}
return res;
}
function FindContinuousSequence(sum)
{
//数学方法 等差数列求和根据序列长度求解
// sum = (n + 1) * n / 2 ;n < 根号2s 根据序列长度进行求解
let res = [];
for(let n = parseInt(Math.sqrt(2 * sum)) ; n >= 2; n--){
if( ((n & 1) === 1 && sum % n === 0) || (sum % n) * 2 === n){ //奇数个序列 偶数个序列
let temp = [];
for(let i = 0, k = parseInt(sum / n - (n - 1) / 2); i < n; k++, i++ ){
temp.push(k);
}
res.push(temp);
}
}
return res;
}
- 求增序数组和的最小值
function FindNumbersWithSum(arr, sum)
{
//首尾计算
let l = 0, r = arr.length - 1 ;
while(l < r){ //1个数时不存在两个数的和
if(arr[l] + arr[r] === sum){
return [arr[l], arr[r]]; //相差越大 值越小
}else if(arr[l] + arr[r] < sum){
l++;
}else{
r--;
}
}
return []; //没有返回[]
}
- 循环移位
function LeftRotateString(str, n)
{
if(n <= 0) return str;
let count = n % str.length;
let arr = str.split('');
swap(arr, 0, count - 1);
swap(arr, count, arr.length - 1);
swap(arr, 0, arr.length - 1);
return arr.join('');
}
//循环移位 交换3次即可
function swap(arr, l, r){
while(l < r){
let temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
l++;
r--;
}
}
function LeftRotateString(str, n)
{
if(!str) return '';
let count = n % str.length;
if(count === 0) return str;
str += str;
return str.substr(n, len);
}
console.log(LeftRotateString('abcXYZdef',3));
- 翻转句子
function ReverseSentence(str)
{
//古老解决 翻转每个单词 根据空格前后判断单词结尾
if(!str.trim()) return str; //去掉空格
let arr = str.split(''), i = 0;
swapStr(arr, 0, arr.length - 1); //翻转整个字符串
while(i < arr.length){ //翻转每个单词 单词定义从开始到空格结束
if(arr[i] !== ' '){
let start = i;
while(arr[i] !== ' ' && i < arr.length){i++};
swapStr(arr, start, i - 1);
}else{
i++;
}
}
return arr.join('');
}
//字符串不可变 基本类型 非引用类型
function swapStr(arr, start, end){
while(start < end){
let temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
start++;
end--;
}
}
- 判断是否是顺子
function IsContinuous(numbers)
{
//数学思维 满足顺子 max - min < 5才成立 即个数 - 1 = max - min 超过5则一定不能组成顺子 不能重复
if(numbers.length !== 5) return false;
let min = 14, max = -1; // max 和min值不能为0
let count = [];
for(let num of numbers){
if(num <0 || num > 14) return false; //异常判断
if(num === 0) continue;
if(!count[num]){
count[num] = 1;
}else{
return false; //重复则不是顺子
}
if(num > max){
max = num;
}
if(num < min){
min = num;
}
if(max - min >= 5) return false; //超过个数一定不能成顺子
}
return true;
}
function IsContinuous(numbers)
{
//数学思维 满足顺子 max - min < 5才成立 即个数 - 1 = max - min 超过5则一定不能组成顺子 不能重复
if(numbers.length !== 5) return false;
let min = 14, max = -1; // max 和min值不能为0
let flag = 0;
for(let num of numbers){
if(num <0 || num > 14) return false; //异常判断
if(num === 0) continue;
if((flag >> num) & 1 === 1) return false; //有重复的移位
flag |= 1 << num;
if(num > max){
max = num;
}
if(num < min){
min = num;
}
if(max - min >= 5) return false; //超过个数一定不能成顺子
}
return true;
}
- 约瑟夫环问题
function LastRemaining_Solution(n, m)
{
if(n < 1 || m < 1) return -1;
let step = 0, i = -1, arr = Array(n), count = n
while(count > 0){
i++;
if(i === n) i = 0;
if(arr[i] === -1) continue; //已经出队
step++; //计步
if(step === m){ //满足条件出队
arr[i] = -1;
step = 0;
count--;
}
}
return i;
}
- 转化成整数
function StrToInt(str)
{
if(!str.trim()) return 0;
let sum = 0, sign = str[0];
if(str.startsWith('-') || str.startsWith('+')){
str = str.slice(1);
}
for(let val of str){
if(val >= '0' && val <= '9'){
sum = sum * 10 + (val - '0');
}else{
return 0;
}
}
sum = (sign === '-') ? -sum : sum;
//判断数据是否溢出 数据范围补码在 -Math.pow(2, 31) Math.pow(2, 31) - 1
if(sum >= -Math.pow(2, 31) && sum <= Math.pow(2, 31) - 1){
return sum;
}else{
return 0;
}
}
- 累乘
function multiply(array)
{
//使用倒三角累乘方法
let res = [], resB = [], result = [];
res[0] = 1;
resB[array.length - 1] = 1;
for(let i = 1; i < array.length; i++){
res[i] = res[i - 1] * array[i - 1];
}
//下三角累乘
for(let j = array.length - 2; j >= 0; j--){
resB[j] = resB[j + 1] * array[j + 1];
}
//累乘
for(let i = 0; i < array.length; i++){
result[i] = res[i] * resB[i];
}
return result;
}
- 字符串匹配
//s, pattern都是字符串 类似最小编辑距离
function match(s, pattern)
{
if(!s && !pattern){ //都为空匹配成功
return true;
}
if(s && !pattern){ //s存在但patter为空匹配失败
return false;
}
//s为空,pattern存在时可能匹配成功 a*a*a* 全为0个字符
//当第二个字符不为*时 正常匹配
if(pattern[1] !== '*'){
if(s[0] === pattern[0] || (s.length !== 0 && pattern[0] === '.')){
return match(s.slice(1), pattern.slice(1));
}else{
return false;
}
}else{
if(s[0] === pattern[0] || (s.length !== 0 && pattern[0] === '.')){
return match(s, pattern.slice(2)) || match(s.slice(1), pattern); //匹配0个或者多个
}else{
return match(s, pattern.slice(2)); //匹配0个 正则表达式后移2个
}
}
}
- 字符流中第一个出现的字符
- 判断是否为整形数字
- 链表中环的入口节点
- 删除链表中的重复节点
笔试编程题
Bigo笔试题(20190827)
- 网页上动态显示距离今年结束倒计时功能
function calNumLength(num){
return num > 9 ? num : '0' + num;
}
function getRemainTime(timeDom){
let year = (new Date()).getFullYear();
let endYear = new Date(year,11,31);
setInterval(() => {
var nowTime = Date.now();
var remainTimeMill = endYear.getTime() - nowTime;
var timeDiff = Math.floor(remainTimeMill / 1000);
//进制转换
var day = parseInt(timeDiff / 3600 / 24);
var hour = parseInt(timeDiff / 3600 % 24);
var minute = parseInt(timeDiff / 60 % 60);
var second = parseInt(timeDiff % 60);
timeDom.innerHTML = `据${year}还有${calNumLength(day)}天${calNumLength(hour)}:${calNumLength(minute)}:${second}`;
},1000);
}
window.onload = () => {
var timeDom = document.getElementById('time');
getRemainTime(timeDom);
}
- 用js实现链表,找出链表中的相同数据,不能重新申请空间
var findSameNum = (li1,li2) => {
var p = li1, q = li2;
var resultList = new Node(0);
var res = resultList;
var sortFlag = 0; //0升序/1降序
if(!p || !q){
return;
}
if(p.data > p.next.data){
sortFlag = 1;//降序
}
while(p && q){
var pData = p.data;
var qData = q.data;
if(pData === qData){
let sameList = new Node(pData);
resultList.next = sameList;
resultList = sameList;
p = p.next;
q = q.next;
}else if(pData > qData){
if(sortFlag){
p = p.next;
}else{
q = q.next;
}
}else{
if(sortFlag){
q = q.next;
}else{
p = p.next;
}
}
}
return res.next;
}
- Excel表的列字母转换,输入第几列,输出列字母组合,看不懂题?(excel列字母数字表示互转 26进制转换)
var letterToNum = (str) => {
//判断是否为空
if(!str){
return ;
}
//判断是否'A-Z'
var newStr = str.toUpperCase();
var regStr = /[A-Z]+/g;
if(!newStr.match(regStr)){
return ;
}
var num = 0, i = 0, bitNum;
while(i < newStr.length){
bitNum = newStr.charAt(i).charCodeAt() - 'A'.charCodeAt() + 1;
//低位累加法
// num += bitNum * Math.pow(26,(newStr.length - i - 1));
//高位累乘法
num = num * 26 + bitNum;
i++;
}
return num;
}
var numToLetter = (num) => {
if(num <= 0){
return ;
}
var resStr = '';
while(num > 0 ){
num--;
resStr = String.fromCharCode(((num % 26) + 'A'.charCodeAt())) + resStr;
num = (num - num % 26) / 26;
}
return resStr;
}
- 无重复数组中找出和target的所有组合方式
- 回溯思想 (dfs栈调用,多维解法)
//括号回溯法 递归 找约束条件 多维值 全局变量 分析问题画出状态树进行递归 一般回溯都用dfs遍历(递归或者栈调用)
//括号回溯法 递归 找约束条件 多维值 全局变量 分析问题画出状态树进行递归 一般回溯都用dfs遍历(递归或者栈调用)
var findCom = (res, k, l, r, str) => {
if(k === 2 * n){
return res.push(str.join(''));
}
if(l < n){
str[k] = '(';
findCom(res, k + 1, l+ 1, r, str);
}
if(r < n && l > r){
str[k] = ')';
findCom(res, k + 1, l , r + 1, str);
}
}
var n = 3;
var res = [];
var str = [];
var l = 0; r = 0; //左右括号数
findCom(res, 0, l, r, str);//第二个参数为括号总数
console.log(res);
- 数组不重复,可重复数字

//递归 二叉树 组合思想
var comSum = (candidates, target, start, temp, res) => {
if(candidates.length === 0){
return;
}
if(target === 0){
res.push(temp.join(""));
return;
}
for(var i = start; i < candidates.length; i++){
var num = target - candidates[i];
if(num >= 0){
temp.push(candidates[i]);
comSum(candidates, num, i, temp, res);
temp.pop();
}
/*else {
return; 当数组是升序时即可打开该代码,应为减去一个小值都小于0,减去一个大值必定小于0,无循环必要
}*/
}
}
var res = [];
var arr = [3, 2, 5];
comSum(arr, 8, 0, [], res)
console.log(res);
- 无重复数字
//排序去掉重复数字 sort()函数默认按字符串来比较
var comSum = (candidates, target, start, temp, res) => {
if(!candidates.length){
return;
}
if(!target){
res.push(temp.slice());
}
for(var i = start; i < candidates.length; i++){
//去除重复元素 i > start 这样重复的时候仍然可以取重复值 i >= 1 将会导致重复值无法取到
if(i > start && candidates[i] === candidates[i - 1]){
continue ; //排序去除重复元素
}
var num = target - candidates[i];
if(num >= 0){
temp.push(candidates[i]);
comSum(candidates, num, i + 1, temp, res);
temp.pop();
}else{
return;
}
}
}
function compare(a, b) {
return a - b; //false不变序 升序排列
}
var arr = [10, 1, 2, 7, 6, 1, 5];
var res = [];
//sort()默认转化为字符串进行ascii码排序
arr.sort(compare);//升序排列
comSum(arr, 8, 0, [], res);
console.log(res);
字节跳动笔试题(20190829)
小米笔试题(20190908)
- 二叉树根据括号表达式中序遍历树
function Node(data){
this.left = this.right = null;
this.data = data;
}
//根据广义表生成树
function createBinTreeByGList(str){
const LEFT_CHILD = 1, RiGHT_CHILD = 2;
let childFlag = 0;
let currenNode = null, root = null;
let stack = [], i = 0, top = -1;
let len = str.length;
// stack装的是相对的父元素,即(左边的元素
while(i < len){
let data = str.charAt(i++);
switch(data){
case '(':
childFlag = LEFT_CHILD;
stack[++top] = currenNode;
break;
case ',':
childFlag = RiGHT_CHILD;
break;
case ')':
childFlag = 0;
top--;
break;
case '':
break;
default:
currenNode = new Node(data);
if(!root){
root = currenNode;
}else{
switch(childFlag){
case LEFT_CHILD:
stack[top].left = currenNode;
break;
case RiGHT_CHILD:
stack[top].right = currenNode;
break;
}
}
break;
}
}
return root;
}
//中序遍历
function inOrderTree(tree, orderArr){
if(tree){
inOrderTree(tree.left, orderArr);
orderArr.push(tree.data);
inOrderTree(tree.right, orderArr);
}
}
var str = '(A(B(C,D),E(,F)))';
var tree = createBinTreeByGList(str);
var orderArr = [];
var res = inOrderTree(tree, orderArr);
- 二叉树交换左右子树
//交换左右子树
function reverseTree(tree){
if(tree){
if(!tree.left && !tree.right){
return;
}
let temp = tree.left;
tree.left = tree.right;
tree.right = temp;
reverseTree(tree.left);
reverseTree(tree.right);
}
}
- 最少商品数,数量不限获取某金额买到的最少商品
回溯思想,同bigo笔试题(转化为商品可重复或者商品不可重复问题)
奇信安笔试题(20190916)
- 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示,2进制转换。
// 补码: 正数的原反补码相同, 负数的反码和补码单独计算 负数的 补码用程序表达则为n(负数) (-n - 1)取反
function NumberOf1(num)
{
// write code here
let res;
if(num >= 0){
res = tenToBin(num, true);
}else{
//-n-1 为补码包括符号位取反前的值 如: n = -3 补码: 11111101取反 00000010 = 2 = -n - 1
res = tenToBin(-num - 1, false);
}
return res;
}
function tenToBin(num, isPositive){
let res = '', count = 0, len = 32;
while(num){
if(num % 2 === 1){
count++;
}
//不用parseInt(num / 2)即可获得商
num = (num - num % 2) / 2;
}
//如果是负数,补码中1的个数 = 0的个数 = 32 - 1的个数
if(!isPositive){
count = len - count;
}
return count;
}
function numberOfone(n){
let count = 0;
for(let i = 0; i < 32; i++){ //计算机中数本来就是用补码表示的,直接移位可获得1的个数
if((n >>> i) & 1 === 1){
count++;
}
}
return count;
}
招商银行笔试题(20190917)
1.在一根数轴上,1~n的每个点上都标有‘L’和‘R’,最初每个点上都有一个机器人,现在所有机器人同时一起执行以下操作10e100次:如果该点上标有‘L’,机器人左移;否则右移。保证点1上为‘R’,点n上为‘L’,最后每个点上有几个机器人?
var robatNum = (directionStr) => {
let res = [];
for(let k = 0; k < directionStr.length; k++){
res[k] = 0;
}
let times = 8;
for(let i = 0; i < directionStr.length; i++){
let index = i, last;
let temp = []; //计算每个机器人最后位置
while(true){
if(directionStr[index] === 'R'){
index++;
}else{
index--;
}
if(temp.includes(index)){
break;
}else{
temp.push(index);
}
}
last = (times - temp.length - 1) % 2; //根据剩下的次数计算最后机器人的位置,推导过程
index = last ? temp.pop() : temp[temp.length - 2];
res[index]++;
}
return res;
}
console.log(robatNum('RRLRL'));
面试编程题
- 实现开根不借助其他工具
//二分法求算术平方根
function sqrtNum(num){
if(num <= 0) return 0;
let low = 1, high = num, precision = 1e-6;
let mid;
while(high - low > precision){
mid = (low + high) / 2;
if(mid * mid === num) return mid.toFixed(6);
if(num > mid * mid){
low = mid;
}else{
high = mid;
}
}
// toFixed() => 四舍5入;
return ((low + high) / 2).toFixed(6);
}
console.log(sqrtNum(3));
- 打印三角形:计算空格和*与行数的关系即可
//打印正三角
function printTriangleII(n){
for(let i = 0; i < n; i++){
let str = '';
for(let j = n - 1; i < j; j--){
str += ' ';
}
for(let k = 0; k <= i; k++){
str += '* ';
}
console.log(str);
}
}
printTriangleII(5);
//打印下三角
function printTriangleIII(n){
for(let i = 0; i < n; i++){
let str = '';
//空格递增1
for(let j = 0; j < i; j++){
str += ' ';
}
//*递减2
for(let k = n; 2 * i < k; k--){
str += '*';
}
console.log(str);
}
}
printTriangleIII(5);
//打印2个下三角
function printTriangleIIII(n){
for(let i = 0; i < n; i++){
let str = '';
for(let k = 0; k < i; k++){
str += ' ';
}
for(let j = n; 2 * i < j; j--){
str += '*';
}
for(let k = 0; k < i; k++){
str += ' ';
}
str += str;
console.log(str);
}
}
printTriangleIIII(5);
- 计数排序
var sortArr = (arr) => {
let countArr = [], min = arr[0], max = arr[0],resArr = [];
//获取计数数组
for(let i = 1; i < arr.length; i++){
if(arr[i] > max){
max = arr[i];
}
if(arr[i] < min){
min = arr[i];
}
}
// 2的16次方 unicode
for(let i = 0; i < max - min + 1; i++){
countArr[i] = 0;
}
//计数
for(let j = 0; j < arr.length; j++){
countArr[arr[j] - min]++;
}
//展开值和下标
let m = 0;
for(let k = 0; k < countArr.length; k++){
while(countArr[k]){
resArr[m++] = k + min;
countArr[k]--;
}
}
/*
//下标为数组值 ,值为相应数组值的结果数组中的下标
for(let j = 1; j < max - min + 1; j++){
countArr[j] = countArr[j] + countArr[j - 1];
}
//返回结果
for(let j = 0; j < arr.length; j++){
resArr[countArr[arr[j] - min] - 1] = arr[j];
countArr[arr[j] - min]--;
}*/
return resArr;
};
var arr = [3, 5, 5, 1, 16,1, 66];
console.log(sortArr(arr));
- 括号匹配
//多种括号匹配配
function validBraces(str) {
let reg = /[\(\{\[]/ ;// 正则表达式选中一个
let arr = [], strArr = str.split('');
for (let value of strArr) {
if (reg.test(value)) {
arr.push(value);
} else {
switch (value) {
case ')':
var temp = arr.pop();
if (temp !== '(') {
return false;
}
break;
case '}':
var temp = arr.pop();
if (temp !== '{') {
return false;
}
break;
case ']':
var temp = arr.pop();
if (temp !== '[') {
return false;
}
break;
}
}
}
return !arr.length;
}
console.log(validBraces('))))'));
var arr = [];