剑指offer快速回忆之面试的基础知识

摘要

语言:Effective JAVA、O1找数组重复数字、二维数组查找、替换空格、反向打印链表、双栈实现队列、斐波那契、旋转数组最小值、减绳子、二进制中1的个数(语言、数组、字符串、查找、排序、链表、栈、递归、回溯、分治、动归、二进制)

语言

语言部分直接跳过,去看Effective系列吧

数据结构

数组

1.找出数组中重复的数字

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
要求1:时间O(n),空间O(1)
要求2:不能改变数组

解要求1
解法一:排序
解法二:HashSet
解法三:
  类似于最小交换次数,因为数字范围是0~n-1,所以排好序的话,大小为x的数字
应该在下标为x的位置。
  从下标i=0开始,扫描nums数组,假设nums[0]=m,若m大于n,用例无效
  	1.若m==i,i++;回到1
  	2.查看nums[m]是否等于m,若等于m扫描结束,找到重复
  	3.若不等于m,交换nums[i]和nums[m];回到1
  	
解要求2
解法一:空间换时间,新开辟一个数组,时间O(n),空间O(n)
解法二:时间换空间 空间O(1)
	只能通过记数来确定了,思路:先统计0~n/2的个数count ,如果count>n/2
表示0~n/2一定有重复的数字,否则n/2~n有重复数字,然后不断缩小范围,确定重复。
	每次数组大小缩小为一半,共缩小logn次,所以时间O(nlogn)
2.二维数组中的查找

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

思路:
	此题如果从左上角或者右下角开始寻找就大错特错了
	正确做法是从右上角或者左下角,
	从右上角开始寻找数字m,设右上角数字为now
解法一:
	1.now>m,则可以排除最右边那一列没有m,矩形变小
	2.now<m,则可以排除最上边那一行没有m,矩形变小
	3.now=m,寻找结束

字符串

3.替换空格

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
.
相关题目:
有两个排好序的数组,A1和A2,内存在A1的末尾有足够的空间能够容纳A2,请实现一个函数,将A2插入A1,并且数组是排好序的。

思路:
	替换会导致字符串变长,所以就会发生数组的复制,时间O(n)
	如果全是空格需要拷贝n次,所以复杂度O(n^2),肯定过不了
	如果从后往前复制呢,就需要直到最后一个字符的位置,我们能获得最后一个字符
	的位置吗?可以遍历+计算,复杂度O(n)
	此题完

链表

4.从尾到头打印链表

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

思路:
	解法一:遍历过去,顺便将链表改造成从尾到头,然后一次打印,在改造回来
	缺陷:打印本来是个只读操作,本不应该修改数据结构的,所以先问好
	解法二:利用一个栈
	解法三:递归

栈和队列

5.两个栈实现队列

用两个栈实现队列

突然发现我之前的思路都是错误的,时间复杂度太高
之前:push(a)时,先将a放到stack2,再将stack1的数据push到stack2,再将stack2的数据push回stack1
正确:stack1是顺序栈,当需要队头的时候,将stack2的栈顶弹出,如果stack2为空,就将stack1的全部数据push到stack2
如下所示:

在这里插入图片描述

6.两个队列实现栈

用两个栈实现队列

思路:
	插入时往queue1,queue2不为空的队列插,弹栈时,将queue1.size()-1个元素插到queue2,queue1的最后那个就是栈顶
	如果不能用queue.size(),可以这么做:如果删除这个元素queue1为空,这个元素就是最后一个元素,就是栈顶,返回就行喽

算法和数据操作

7.斐波那契数列

求斐波那契数列的第n项
要求:时间O(longn)

在这里插入图片描述
在这里插入图片描述
二分查找、各种排序算法、特别是快排各种实现一定要烂熟于胸

查找和排序

7.旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。

二分思路并不难,
有一点细节要想明白,最后两个指针,一定是在大数组末尾和小数组开头

回溯

动态规划和贪心

8.减绳子

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m] 。请问 k[0]k[1]…*k[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

动归:O(n^2) 不在多解释
贪婪:当n>=5时,将绳子拆成尽可能多的3,当n=4时将升子拆成两个2

位运算

9.二进制中1的个数

请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

拓展1:判断一个数是不是2得整数次幂O(1)
拓展2:给定m和n,求m的二进制变成n的二进制需要改变的位数

思路:(我连最简单的这个思路都没想到哭了😭)
解法一:将n与1进行与运算得最低位的二进制,n>>1,重复此操作
(有个弊端,就是当n<0的时候,容易死循环>>带符号右移,>>>无符号右移,<--别用)
解法二:将n与flag=1进行与运算得到最低位的二进制,flag<<1,重复此操作
解法三:将n减1,n的二进制有什么变化呢:最右边的1变成0,最后边连续的0变成连续的1
	   比如  11000  减一
		得   10111
	再将11000&10111得10000,可以消除一个1
步骤:将n与n-1与预算得新的n,不断重复此操作,重复几次就有多少个1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值