西瓜仔刷题集1--剑指offer(1-20题)

本文介绍了多种数据结构和算法问题的解决方案,包括二维数组中查找整数、字符串空格替换、链表逆序打印、重构二叉树、用两个栈实现队列、斐波那契数列、旋转数组找最小值、跳跃游戏、变态跳跃游戏、矩形覆盖问题以及浮点数求幂。涉及到了递归、动态规划、链表操作和二叉树遍历等核心概念。
摘要由CSDN通过智能技术生成

1.在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。【2022.3.16】

选择最左下角的那个点作为起始点,
也就是a[array.lenth][0],比它大就往右边走,
比它小就往上面走。

2.请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。【2022.3.16】

  return str.replace(/\s/g, '%20');
\s:正则表达式判断空格;
//g:全局判断

3.输入一个链表,从尾到头打印链表每个节点的值。【2022.3.17】
把链表遍历一遍,用头部添加的方式放到新数组中

 while(head!==null){
        str.unshift(head.val);
        head=head.next;
    }
    如何定义一个链表测试!!
    function ListNode(val) {
    this.val = val;
    this.next = null;
 }

// 创建新的节点
let node1 = new ListNode(1);
let node2 = new ListNode('kk');
let node3 = new ListNode('ff');
node1.next = node2;
node2.next = node3

var a=printListFromTailToHead(node1);
  console.log(a);

【2022.3.18】.知前序,中序重构二叉树

找到根节点,划分左子树,右子树
左右子树在分别递归遍历;
pre是前序遍历集合;Min是中序遍历集合;
return
{
left:reConstruct(pre.slice(1,index+1),left),
right:reConstruct(pre.slice(index+1),right)
};

【2022.3.18】.用两个栈实现队列
一个栈是入栈,一个栈是出栈;

outstack.push(instack.pop);
return  outstack.pop
注意边界条件的判断:
 if (!outStack.length) {
    while (inStack.length)

昨天周六,休息一天
【2022.3.20】动态规划求解斐波拉契数列

动态规划的求解意思为:每一步的求解都用到上一次算出的答案;例如计算第三项的时候用第二项加第一项;
注意边界条件:n=1的时候已经直接输出,不做循环了
  while (n--) {
    g += f;
    f = g - f;
  }
  return f;

【2022.3.21】6.旋转数组中的最小数字

只要找到数组中下一个数值小于前一个数值的临界点,即为最小值
 for (let i = 0; i < rotateArray.length; i++) {
    if (rotateArray[i] > rotateArray[i + 1]) return rotateArray[i + 1];
  }
  return rotateArray[0];

【2022.3.21】8.一只青蛙一次可以跳上1级台阶,也可以跳上2级。

斐波拉契问题变形:用动态规划问题求解
1.当第一步跳一个台阶时,剩下的跳法为f(n-1)
2.当第一步跳2个台阶时,剩下的跳法为f(n-2)
因此f(n)=f(n-1)+f(n-2);
判断初始条件:
有一个台阶,f(1)=1;
有两个台阶,f(2)=2;
ps!注意边界条件 while (--number)

  let f = 1,//f为第一项
    g = 2;//g为第二项
  while (--number) {
    g += f;
    f = g - f;
  }
  return f;
}
斐波拉契这一类问题的常规写法:
       if(number <= 0)
            return 0;
        else if(number == 1)
            return 1;
        else if(number == 2)
            return 2;
        else
            return jumpFloor(number-1) + jumpFloor(number-2);
    }

【2022.3.21】9. 变态跳台阶:一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
解题思想:

a[n]=a[n-1]+a[n-2]+......+a[1];..........................①
a[n-1]=        a[n-2]+......+a[1];..........................②
两式相减可知:a[n]=2*a[n-1];

【2022.3.22】10.21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法
思考:变相的斐波拉契数列问题
n=0; return 0;
n=1;f(1)=1;
n=2;f(2)=2;
其余条件下:在这里插入图片描述
【2022.3.22】
一个一个向右移位,并且判断最右边的那个位是否为1,为1就count++,但是这样输入负数时会陷入死循环,因为负数右移时,最高位补得是1,那么这样会有无数个1。
因此选择把flag: 1 左移;
1左移 32 位后为 0;

```cpp
 while(flag){
    if(flag&n)
        count++;
        flag=flag << 1;
    }
    return count;```

【2022.3.22】【❤❤❤】这该死的题看了两天
12.给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

解法一:按位求解
此方法将幂次k看做二进制的数,一位一位的求解。比如k=10,即求a10,
10的二进制表示为1010。我们就可以把a10看成a8+a2。
就是对应二进制位为1的位置求幂,最后在相加。
这样就可以遍历幂次n的每个位来完成求幂运算
  while (n) {
    // 也可以用递归做,这里采用了循环
    if (n & 1)
      // 为1的时候把结果乘上去
      {res *= base;}
    base *= base;//底数翻倍
    n >>= 1;//n右移动一位,继续判断下一位 
  }

解法二:递归求解
int pow1(int a,int k){
	if(k==0) return 1;
	else{
		if(k%2) return a*pow(a,k-1);
		else{
			int tmp=pow(a,k/2);
			return tmp*tmp;
		} 
	}
}
知识点1:对于if(!a)来说,要看你给a的初值是什么,如果是一个非零值的话,那么!a就是假,不执行语句;
如果a的初值为零,那么!a就是真,执行语句
知识点2:左移和右移

【2022.3.24】(13)调整数组顺序使奇数位于偶数前面
思路:先找到奇数的个数,遍历数组每一个值:
是奇数的话,下标从0开始,放入新数组;
是偶数的话,下标从奇数个数下表开始奇数个数下标加一开始;

 for (let i = 0; i < array.length; i++) {
    if (array[i] & 1) {
      newArray[oddBegin++] = array[i];
    } else {
      newArray[oddCount++] = array[i];
    }
  }

【2022.3.24】(14)链表中倒数第K个节点

双指针:一个在1,另一个在k;同时跑,
当一个指针达到最后一个时,那么前一个指针就是倒数第k个;

【2022.3.25】(15)反转链表:规定了必须用链表
:使用三个指针遍历单链表,逐个链接点进行反转。
1->2->3->4->5;(按照以下过程)
1->null;
2->1->null;
3->2->1->null;
4->3->2->1->null;
5->4->3->2->1->null; 最后返回5,就是新链表的头结点

 // 三个节点
    let preNode=null,aftNode=null;
    while(pHead!==null){
        aftNode=pHead.next; //记录下一节点
        pHead.next=preNode;//指向前一节点
        preNode=pHead;//当前头结点成为下次被指向的前一结点
       pHead =aftNode;//当前下一节点成为新的头结点
    }
    return preNode;//最后一次被指向的前节点就是反转链表的头结点

【2022.3.25】16.合并两个排序的链表  
递归实现:两个链表都是单挑递增的
不断地比较他们的头结点即可

  if(pHead1.val<pHead2.val){
        NewListHead=pHead1;
        NewListHead.next=Merge(pHead1.next,pHead2);}
       else{
        NewListHead=pHead2;
        NewListHead.next=Merge(pHead2.next,pHead1);
        }
        
     return NewListHead;

【2022.3.28】17.树的子结构 (B是A的子结构)
HasSubtree:判断 B 是否是 A 的子结构:从根节点开始判断,根节点相等的情况下,调用子函数判断;如果根节点不相等,下移A的根节点继续递归判断
IsSubtree:封装“判断 B 是否是 A 的子结构”的具体逻辑。不断遍历传入根节点的左右子树判断

function HasSubtree(pRoot1, pRoot2)
{
    let result=false;
    if(pRoot1==null||pRoot2==null) return false;
    if(pRoot1.val==pRoot2.val) result=IsSubtree(pRoot1,pRoot2);
 //该根节点不等,下移A的根节点
    if(!result) result= HasSubtree(pRoot1.left,pRoot2);
    if(!result) result= HasSubtree(pRoot1.right,pRoot2);
    return result;
}
function IsSubtree(pRoot1, pRoot2)
{
//B都判等完了,说明B为A的子树
    if(pRoot2==null) return true;
//A都判等完了还在继续找,说明B不是A的子树
    if(pRoot1==null) return false;
   
    if(pRoot1.val!==pRoot2.val) return false;
    return IsSubtree(pRoot1.left,pRoot2.left)&&IsSubtree(pRoot1.right,pRoot2.right);
    
}

【2022.3.28】18.二叉树的镜像  
思想:交换左右节点,递归

 if(pRoot==null) return null;
    [pRoot.right,pRoot.left]=[pRoot.left,pRoot.right];
    Mirror(pRoot.left);
    Mirror(pRoot.right);
    return pRoot;

【2022.3.28】20.包含min函数的栈
实现栈的min函数:增加一个辅助栈
pop函数:原栈直接压入元素;minStack压入时比较一下

if(temp==null)  
//temp等于空意味着第一次比较,这是直接把元素放进去即可;
//temp=node;用来记录元素,用于后续比较
{   temp=node;
    stack.push(node);
    minStack.push(node);}
//temp不为空意味着后续比较,压入之前和temp记录数值比较一下,
//temp始终记录最小值
else{
    if(node<temp){
        temp=node;
    }
    stack.push(node);
    minStack.push(temp);
   
}

【2022.3.30】19.顺指针打印矩阵
【❤❤❤】这该死的题看了两天
定义两个函数:
1.通过两个坐标确定矩阵打印范围
2.根据坐标打印一整圈

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值