1.二维数组的查找
function FindArray(arr){
return arr.some(arr=>arr.some(e=>e===target))
}
- 数组排序
function SortArray(arr){
return array=arr.sort((a,b)=>a-b)
}//升序
2.替换空格
function replaceSpace(str){
return arr.replace('/\s/g','%20')
}
3.从尾到头打印链表
链表:数组之间加指针 p.head p.next
function printListFromTailToHead(head){
var p=head
var result=[]
while(p){
result.unshift(p.val)//从尾到头
//result.shift(p.val)//从头到尾
p=p.next
}
return result
}
4.重建二叉树
- 二叉树遍历:
- 前序遍历(先序):根|左|右(下面的也是先根再左后有)
- 中序遍历:左下开始,左|根|右(都是左下开始)
- 后序遍历:左下开始,左|右|根
function TreeNode(x){
this.val=val
this.left=null
this.right=null
}
//pre前序;Vin中序
function TreeReBulit(pre,vin){
if(pre.length===0||vin.length===0){
return null
}
var index=vin.indexOf(pre[0])//找根
var left=vin.slice(0,index)
var right=vin.slice(index+1)
var node=new TreeNode[pre[0]]
node.left=TreeReBulit(pre.slice(1,index+1),left)//前序,后序,递归
node.right=TreeReBulit(pre.slice(index+1),right)
return node
}
5.两个栈实现队列
- js一个栈就可以
var stack1=[]
function push(node)
{
stack1.push(node)//队列中enqueue直接push即可(clear也不需要)
}
function pop()
{
// write code here
return stack1.shift()//其他均需要return
}
知识点:完整的队列类的实现
function Queue(){
var items=[]
this.enqueue=function(element){
items.push(element)
}//添屁股--添后
this.dequeue=function(){
return items.shift()
}//删头头--与栈不同,先入先出,删头
}
6.旋转数组的最小数字
function minNumberInRotateArray(rotateArray)
{
// write code here
if(rotateArray.length===0){
return 0
}
var array=[]
array=rotateArray.sort((a,b)=>a-b)
return array[0]
}
//终于上道了,自己第一个完全通过的js代码哈哈哈哈哈哈
7.斐波那契数列
function Fibonacci(n)
{
// write code here
if(n===0)
return 0
if(n===1||n===2){
return 1
}
return Fibonacci(n-1)+Fiboacci(n-2)
}//递归会产生栈的溢出
//普通方法
function Fibonacci(n)
{
// write code here
var f0=0,
f1=1,
fn=1
for(let i=2;i<=n;i++){
fn=f0+f1
f0=f1
f1=fn
}
if(n===0){
return 0
}else{
return fn
}
}
8.跳台阶(一次只跳一阶或二阶)
//通过带入数值发现规律--本质为斐波那切数列
function jumpFloor(number)
{
// write code here
if(number===0||number==1){
return 1
}
return jumpFloor(number-1)+jumpFloor(number-2)
}
9.跳台阶(一次可跳到n阶)
//通过带入数值发现规律--本质为2*f(n-1)
function jumpFloorII(number)
{
// write code here
if(number===0||number===1){
return 1
}
return jumpFloorII(number-1)*2
}
10.矩形覆盖
//通过带入数值发现规律--本质为f(n-1)+f(n-2)
//注意边界问题
function rectCover(number)
{
// write code here
if(number<=2){
return number
}
return rectCover(number-1)+rectCover(number-2)
}
11.二进制中1的个数
- 二进制码相关知识
- 原码:符号位加上真值的绝对值,第一位表示符号(0正;1负)
- 反码: 正数是本身;负数符号位不变,其余各个位取反.
- 补码:正数是本身;负数 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
- js中的整数的表示范围是[-2^31, +2^31-1],即[-2147483648, +2147483647],
- 需要注意的API
- number.toString(),不传参转为字符串 ;传参转为进制数字符串
- Array.from();将伪数组转化为真正的数组
- array.filter();过滤,符合条件的返回一个新数组
- array.some();遍历,有一个符合条件返回true
- array.every();遍历,全符合条件返回true
//第一次写的;走了弯路,只能完成大于0的数字,对负数没办法判断
function NumberOf1(n)
{
// write code here
arr=Array.from(n.toString(2))
return (arr.filter(e=>e==1)).length
}
//正确方法,注意最底层的思路,对位操作符号应该熟悉
function NumberOf1(n)
{
// write code here
var count = 0,flag=1;
while(flag){
if(n&flag)count++;
flag=flag<<1;
}
return count;
}
12.数值的整次方
- a**b
- Math.pow(a,b)
function Power(base, exponent)
{
// write code here
if(base===0&&exponent===0){
return null
}
return base**exponent
}
//或 Math.pow(base,exponent)
13.调整数组顺序使奇数位于偶数前面
- array.filter()
- array.concat();参数为字符串;参数为数组前后拼接
function reOrderArray(array)
{
// write code here
arr1=array.filter(e=>e%2===1)
arr2=array.filter(e=>e%2===0)
return arr1.concat(arr2)
}
14.链表中倒数第k个结点
//这个方法真的妙,将链表转化成数组,直接根据位置打印出数据即可,太妙了
/*function ListNode(x){
this.val = x;
this.next = null;
}*/
function FindKthToTail(head, k)
{
var arr = [];
while(head!=null){
arr.push(head);
head = head.next;
}
return arr[arr.length-k];
}
//这种方法还不太理解
function FindKthToTail(head, k)
{
var p = head
var q = head
for(var i = 0; p && i< k; i++){
p= p.next
}
if( i < k ){
return null
}
while(p != null ){
p = p.next
q = q.next
}
return q
}
15.反转链表
- 利用数组push pop与链表转换,注意返回值根据题目要求
- 链表的本质就是数组元素前后加指针
/*function ListNode(x){
this.val = x;
this.next = null;
}*/
function ReverseList(pHead)
{
// write code here
var arr=[]
var node=pHead
while(node!=null){
arr.push(node.val)
node=node.next
}
//执行到这里node为null
node=pHead
while(node!=null){
node.val=arr.pop()
node=node.next
}
return pHead
}
16.合并两个排序的链表
- 注意链表是对象,要用list={},不是数组,是每个元素带有指向的数组
- 自己代码的问题需要再研究一下(自己看了好久没看出来)
//自己写的代码,有问题
/*function ListNode(x){
this.val = x;
this.next = null;
}*/
function Merge(pHead1, pHead2)
{
// write code here
var node1=pHead1
var node2=pHead2
var node3
var arr=[]
var array=[]
while(node1.next!=null){
node1=node1.next
}
node1.next=node2
while(node1.next!=null){
arr.push(node1.val)
node1=node1.next
}
array=arr.sort((a,b)=>a-b)
node1=pHead1
while(node1.next!=null){
node1.val=arr.shift()
node1=node1.next
}
return pHead1
}
//正确的代码
function Merge(pHead1, pHead2) {
// write code here
if (pHead1 == null) {
return pHead2;
} else if (pHead2 == null) {
return pHead1;
}
var result = {};
//哪个小先把哪个放在新的链表里面
if (pHead1.val < pHead2.val) {
result = pHead1;
result.next = Merge(pHead1.next, pHead2);
//小的在前面,然后把剩下的再比较
} else {
result = pHead2;
result.next = Merge(pHead1, pHead2.next);
}
return result;
}
17.树的子结构
//有点抽象,我的思路,首先A||B无论谁为空都返回null
//找,找A中有无,有的话从B的根节点
//找到的话找B的左子树在 找到的 A中的左子树中找根 然后 找B的右子树
//当B全部遍历完之后,如果有一个错误,则返回false
//其余的均返回true
//正确答案
/* function TreeNode(x) {
this.val = x;
this.left = null;
this.right = null;
} */
function HasSubtree(pRoot1, pRoot2)
{
if(pRoot2==null || pRoot1==null)
return false;
return isSubtree(pRoot1,pRoot2)||
HasSubtree(pRoot1.right,pRoot2) ||
HasSubtree(pRoot1.left,pRoot2);
}
function isSubtree(pRoot1,pRoot2){
if(pRoot2 == null) return true;
if(pRoot1 ==null) return false;
if(pRoot1.val == pRoot2.val){
return isSubtree(pRoot1.left,pRoot2.left) &&
isSubtree(pRoot1.right,pRoot2.right);
}else{
return false;
}
}
//另一种正确的解法
function HasSubtree(p1, p2, flag) {
var f = HasSubtree;
if(flag && !p2) return true;
if(!p1 || !p2) return false;
if(p1 && p2 && p1.val == p2.val)
return f(p1.left,p2.left,true) && f(p1.right,p2.right,true) || f(p1.left,p2)||f(p1.right,p2);
return f(p1.left,p2) || f(p1.right,p2);
}
18.二叉树的镜像
- 左右互换,递归下去
/* function TreeNode(x) {
this.val = x;
this.left = null;
this.right = null;
} */
function Mirror(root)
{
// write code here
if(root==null){
return null
}else if(!root.left&&!root.right){
return null
}
var t={}
t=root.left
root.left=root.right
root.right=t
if(root.left){
Mirror(root.left)
}
if(root.right){
Mirror(root.right)
}
return root
}
19.顺时针打印矩阵
function printMatrix(matrix)
{
//为空返回null
if(matrix==''||matrix.length==0){
return null;
}
var a=matrix.length;
var b=matrix[0].length;
var r=matrix.length,
c=matrix[0].length;
var result=[],
start=0;
//当
while(r>2*start&&c>2*start){
var endx=c-start;
var endy=r-start;
for (var i = start; i < endx; i++) {
result.push(matrix[start][i])
}
if(start<endy-1){
for (var j= (start + 1); j < endy; j++) {
result.push(matrix[j][endx-1]);
}
}
if(start<(endx-1)&&start<(endy-1)){
for (var m = endx-2; m >= start; m--) {
result.push(matrix[endy-1][m])
}
}
if(start<(endx-1)&&start<endy){
for (var n = endy - 2; n >= start+1; n--) {
result.push(matrix[n][start])
}
}
start++
}
return result;
}
20.包含min函数的栈
- 栈的实现:push返回的是新的长度,但stack此时为改变的数组(unshift也一样)
- pop与shift均返回的是删除的元素,stack为执行之后的数组
var stack = [];
var minStack = [];
function push(node)
{
stack.push(node);
//若最小栈里面数值大于新插入的node,则将这个node也push到min栈里面
if( minStack.length === 0 || minStack[minStack.length - 1] > node){
minStack.push(node);
}
}
function pop()
{
// 为空返回null
if( stack.length === 0 ){
return null;
}
//不为空则删除,
var node = stack.pop();
if( minStack[minStack.length - 1] === node){
minStack.pop();
}
return node;
}
function top()
{
if(stack.length === 0){
return null;
}else{
return stack[stack.length - 1];
}
}
function min()
{
if(minStack.length === 0){
return null;
}else{
return minStack[minStack.length - 1];
}
}
21.栈的压入、弹出序列
function IsPopOrder(pushV, popV) {
var stack = [];
var idx = 0;
for (var i = 0; i < pushV.length; i++) {
stack.push(pushV[i]);
//遍历,入栈
//当栈有序列并且栈顶为出栈的序列时候,出栈
while (stack.length && stack[stack.length - 1] == popV[idx]) {
stack.pop();
idx++;
}
}
//完全出栈后如果stack长度为0,则说明该pop序列是该pushV序列的弹出
return stack.length == 0;
}
22.从上往下打印二叉树
- 看成一个队列,先根|再左|后右;每次打印根的时候,将左右子树全部放到队列里面,然后根据顺序再往下打印;看成队列看成队列看成队列(自己就是这里没想明白,用队列一下就解决了)
- 善用中间数组,数组的四个基本属性有大用处
function PrintFromTopToBottom(root)
{
// write code here
var arr=[];
var data=[];
if(root!=null){
arr.push(root);
}
while(arr.length!=0){
var node=arr.shift();
if(node.left!=null){
arr.push(node.left);
}
if(node.right!=null){
arr.push(node.right);
}
data.push(node.val);
}
return data;
}
23.二叉搜索树的后序遍历序列
- splice从数组中删除指定的一个或多个元素,返回结果为新的数组,会改变原数组
//我写的代码的问题:只判断了去掉根节点数组为递增序列
function VerifySquenceOfBST(sequence)
{
// write code here
var arr=[]
var t='Yes'
if(sequence.length==0){
return false
}
sequence.pop()
for(let i=0;i<sequence.length;i++){
if(sequence[i]<sequence[i-1]){
return t='No'
}
}
return t
}
//正确的代码1,循环跑的比较多,比较费内存
思路为所有大于根节点和小于根节点的长度下来等于总长则正确,如果
function VerifySquenceOfBST(sequence) {
if (!sequence.length) return false;
var count = 0;
var len = sequence.length;
while (len) {
len--
var root = sequence[len] //后序遍历的最后一个是根节点,然后根节点随len变化
while (sequence[count] < root) count++; //左子树上所有结点的值均小于它的根结点的值
while (sequence[count] > root) count++;//右子树上所有结点的值均大于它的根结点的值;
if (count < len){
return false; //左右子树所有大于或小于根节点的值和count===0才能代表是二叉搜索树
count = 0; //进入下一根节点
}
}
return true;
}
//正确思路代码
function VerifySquenceOfBST(sequence) {
if(sequence.length==0){
return false;
}
var root = sequence.pop();
if(sequence.length==0){
return true;
}//只有一个root的1长度也满足条件,返回true
//找出根节点的左节点,将位置记录为idx
var idx = -1;
for (var i = 0; i < sequence.length - 1; i++) {
if (sequence[i] > root) {
idx = i;
break;
}
}
//找右子树,用splice已经将数组右子树切割,sequence为左子树
var righttree = idx == -1 ? [] : sequence.splice(idx);
var lefttree = sequence;
var right = righttree.every(e=>e>root)
//一直执行下去,保证每个左右子树都符合后序遍历 ,返回true
if (right) {
if (lefttree.length == 0) {
return VerifySquenceOfBST(righttree);
} else if (righttree.length == 0) {
return VerifySquenceOfBST(lefttree);
} else {
return VerifySquenceOfBST(lefttree) && VerifySquenceOfBST(righttree);
}
} else {
return false;
}
}
24.二叉树中和为某一值的路径
- slice从数组中提取指定的一个或多个元素,返回结果为新的数组
function FindPath(root, expectNumber) {
var result = [];
if (root === null) {
return result;
}
dfsFind(root, expectNumber, [], 0, result);
return result;
}
function dfsFind(root, expectNumber, path, currentSum, result) {
currentSum += root.val;
path.push(root.val);
if (currentSum == expectNumber && root.left == null && root.right == null) {
result.push(path.slice(0));
//这一步将找出来的直接到叶节点的路径先打印出来
}
if (root.left != null) {
dfsFind(root.left, expectNumber, path, currentSum, result);
}
if (root.right != null) {
dfsFind(root.right, expectNumber, path, currentSum, result);
}
//都不满足则删除这个node.val,往上后退一步 ,再找右子树
path.pop();
}
25.复杂链表的复制
26.二叉搜索树与双向链表
27.字符串的排列
//正确的思路,方式1
var result = [];
function Permutation(str){
result = []
if(str.length<=0) return result;
var sortTmp = "";
var arr = str.split("");
result = sortString(arr,sortTmp)
return result;
}
function sortString(arr,sortTmp){
if(arr.length ==0 ){
result.push(sortTmp);
}else{
var isRepeated = {}
for(var i = 0; i<arr.length; i++){
if(!isRepeated[arr[i]]){
var p = arr.splice(i,1)[0];
sortTmp += p;
sortString(arr,sortTmp);
arr.splice(i,0,p); //恢复字符串
sortTmp = sortTmp.slice(0,sortTmp.length-1);
isRepeated[p] = true;
}
}
}
return result;
}
//第二种,递归的方式
function Permutation(str)
{
// write code here
if(str.length == 0)return '';
let str_arr = str.split('');
str_arr.sort();
let res = [];
for(let i = 0; i < str_arr.length; i++){
if(i > 0 && str_arr[i] === str_arr[i-1])continue;
let front = str_arr.slice(0,i);
let end = str_arr.slice(i+1);
PermutationHelp(res,str_arr[i],front.concat(end));
}
return res;
}
function PermutationHelp(res,temp, arr){
if (arr.length === 0) {
res.push(temp);
} else {
for(let i = 0; i < arr.length; i++){
if(i > 0 && arr[i] === arr[i-1])continue;
let front = arr.slice(0,i);
let end = arr.slice(i+1);
PermutationHelp(res,temp+arr[i],front.concat(end));
}
}
}
//我的代码,有问题
function Permutation(str)
{
// write code here
var arr=[]
arr=str.split('')
if(arr.length<=0){
return []
}
for(let i=0;i<arr.length;i++){
for(let j=i+1;j<arr.length;j++){
var t=arr[i]
arr[i]=arr[j]
arr[j]=t
}
return arr.join('')
}
}
28.数组中出现次数超过一半的数字
//正确方式
function MoreThanHalfNum_Solution(numbers)
{
// write code here
var len=numbers.length;
if(len==0)return 0;
var num=numbers[0];
count=1;
for(var i=0;i<len;i++){
if(num==numbers[i]){
count++;
}else{
count--;
}
if(count==0){
num=numbers[i];
count=1;
}
}
count=0;
for(var i=0;i<len;i++){
if(numbers[i]==num)count++;
}
if(count*2>len)return num;
return 0;
}
//我的代码
function MoreThanHalfNum_Solution(numbers)
{
// write code here
var t=0
if(numbers.length==0){
return t
}
var arr=numbers.sort((a,b)=>a-b)
var index=0
for(let i=0;i<arr.length-1;i++){
if(arr[i]==arr[i+1]){
t=arr[i]
index++
}else{
index=0
}
if(index>(arr.length/2)){
return t
}
}
}
29.二维数组的查找
30.二维数组的查找
1.二维数组的查找