知识点与解题思路
- 1、剑指Offer-03 数组中重复的数字
- 2、剑指Offer-04 二维数组中的查找
- 3、剑指Offer-05 替换空格
- 4、剑指 Offer 06. 从尾到头打印链表
- 5、剑指 Offer 07. 重建二叉树
- 6、剑指 Offer 09. 用两个栈实现队列
- 7、剑指 Offer 10- I. 斐波那契数列
- 8、剑指 Offer 10- II. 青蛙跳台阶问题
- 9、剑指 Offer 11. 旋转数组的最小数字
- 10、剑指 Offer 12. 矩阵中的路径
- 11、剑指 Offer 13.机器人的运动范围
- 12、剑指 Offer 14- I. 剪绳子
- 13、剑指 Offer 15. 二进制中1的个数
- 14、剑指 Offer 16. 数值的整数乘方
- 15、剑指 Offer 17. 打印从1到最大的n位数(简单)
- 16、剑指 Offer 18. 删除链表的节点(简单)
- 17、剑指 Offer 19. 正则表达式匹配(困难)
- 18、剑指 Offer 20. 表示数值的字符串
1、剑指Offer-03 数组中重复的数字
一、知识点
(1)Hashset的使用
二、解题思路
class Solution {
public static int findRepeatNumber(int[] nums) {
HashSet<Integer> set = new HashSet<>();
for (int i=0;i<nums.length;i++){
if (set.add(nums[i])==false){
return nums[i];
}
}
return -1;
}
}
2、剑指Offer-04 二维数组中的查找
一、知识点
(1)二维数组的使用
- 创建二维数组的方法:int [][] array = new int[6][6];int [][] array = {{1,2,3},{1,2,3},{1,2,3}};
- 获取二维数组的行:matrix.length;
- 获取二维数组的列:matrix[0].length;
二、解题思路
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
//获取二维数组的长和宽
int length = matrix.length;
if(length==0) return false;
int width = matrix[0].length;
if(width==0) return false;
for(int i=0;i<length;i++){
if(target>=matrix[i][0] & target<=matrix[i][width-1]) {
for(int j =0 ;j<width;j++){
if(target==matrix[i][j]) return true;
}
}
}
return false;
}
}
3、剑指Offer-05 替换空格
一、知识点
(1)StringBuilder的使用
(2)字符串与数组之间的转换
二、解题思路
class Solution {
public String replaceSpace(String s) {
//创建一个StringBUilder,保存结果
StringBuilder result = new StringBuilder();
for(Character x : s.toCharArray()){
if(x==' ') result.append("%20");
else result.append(x);
}
return result.toString();
}
}
4、剑指 Offer 06. 从尾到头打印链表
一、知识点
(1)Java中栈的使用
二、解题思路
class Solution {
public int[] reversePrint(ListNode head) {
LinkedList<Integer> stack = new LinkedList<Integer>();
while(head!=null){
stack.addFirst(head.val);
head=head.next;
}
int[] res = new int[stack.size()];
for(int i=0;i<res.length;i++){
res[i] = stack.removeFirst();
}
return res;
}
}
5、剑指 Offer 07. 重建二叉树
6、剑指 Offer 09. 用两个栈实现队列
一、知识点
(1)Java中栈的使用
二、解题思路
-
使用LinkedList实现栈A、B;
-
通过 A栈进行入队操作,只需执行进栈操作即可;
-
通过B栈进行出队操作,由于要实现队列,需要将A栈中的元素出栈进去B栈,此时B中的元素为倒序;出队时只需要执行B栈的出栈操作即可;
-
当B中还存在元素时,直接进行出栈即可;
class CQueue {
LinkedList<Integer> A, B;
public CQueue() {
A = new LinkedList<Integer>();
B = new LinkedList<Integer>();
}
public void appendTail(int value) {
A.addLast(value);
}
public int deleteHead() {
//若B是非空,表明B中已存在倒序元素,直接进行出栈
if(!B.isEmpty()) return B.removeLast();
//若A也是空,返回-1
if(A.isEmpty()) return -1;
//将A中的元素倒序放入B中
while(!A.isEmpty()){
B.addLast(A.removeLast());
}
return B.removeLast();
}
}
7、剑指 Offer 10- I. 斐波那契数列
一、知识点
(1)动态规划
二、解题思路
class Solution {
public int fib(int n) {
int a=0;
int b=1;
int sum;
for(int i=0;i<n;i++){
sum = (a+b)%1000000007;
a=b;
b=sum;
}
return a;
}
}
8、剑指 Offer 10- II. 青蛙跳台阶问题
一、知识点
(1)动态规划
二、解题思路
- n个台阶的跳法可以由(n-1)个台阶和(n-2)个台阶推出,得递推关系式为:f(n) = f(n-1) + f(n-2)
- 使用动态规划进行解题。
class Solution {
public int numWays(int n) {
int a=1;
int b=2;
int sum;
for(int i=0;i<n-1;i++){
sum =(a+b)%1000000007;
a=b;
b=sum;
}
return a;
}
}
9、剑指 Offer 11. 旋转数组的最小数字
一、知识点
(1)二分查找
二、解题思路
方法1:遍历找旋转点
class Solution {
public int minArray(int[] numbers) {
int result=numbers[0];
for(int i=0;i<numbers.length-1;i++){
if(numbers[i]>numbers[i+1]){
result = numbers[i+1];
break;
}
}
return result;
}
}
方法二:二分查找
class Solution {
public int minArray(int[] numbers) {
int L=0;
int R=numbers.length-1;
int mid;
while(L<R){
mid = L + (R-L)/2;
if(numbers[mid]>numbers[R]) L=mid+1;
else if(numbers[mid]<numbers[R]) R=mid;
else R--;
}
return numbers[R];
}
}
10、剑指 Offer 12. 矩阵中的路径
一、知识点
(1)DFS+可行性剪枝
二、解题思路
11、剑指 Offer 13.机器人的运动范围
一、知识点
(1)DFS+可行性剪枝
二、解题思路
class Solution {
int res;
boolean[][] marked;
public int movingCount(int m, int n, int k) {
marked = new boolean[m][n];
dfs(0,0,m,n,k);
return res;
}
public void dfs(int x,int y, int m, int n ,int k){
if(x>=m || y>=n || marked[x][y] || sum(x)+sum(y)>k) return;
marked[x][y] = true;
res++;
dfs(x+1,y,m,n,k);
dfs(x,y+1,m,n,k);
}
public int sum(int x){
int sum = 0;
while(x!=0){
sum+=x%10;
x=x/10;
}
return sum;
}
}
12、剑指 Offer 14- I. 剪绳子
一、知识点
(1)动态规划
(2)贪心算法
(3)大数取余
二、解题思路
思路一:动态规划(1<n<59)
- 将长度为 i 的绳子分成 j 和 i-j ,那么 dp[i] 可以由 j 和 i-j推出,其中 j 和 i-j可能需要再分,也可能不需要再分,要根据 j 与 dp[j] 的大小关系进行确定;
- dp[i] = max { dp[j] , j }* max { dp[i-j] , i-j }
- 对j从2至i/2进行遍历,选择结果最大的切割方案。
class Solution {
public int cuttingRope(int n) {
if(n==2) return 1;
int[] dp = new int[n+1];
dp[2] = 1;
dp[3]=2;
for(int i=4;i<n+1;i++){
int max = 0;
for(int j=2; j<=i/2;j++){
int temp = Math.max(dp[j],j)*Math.max(dp[i-j],i-j);
if(temp>max) max =temp;
}
dp[i]=max;
}
return dp[n];
}
}
思路二:贪心算法(1<n<1000)
- 切割出来的小段绳子中,长度为3的越多,结果越大;
- 使用循环求余法进行求余;
class Solution {
public int cuttingRope(int n) {
long res=1; //由于res*3可能超出int32的范围,例如res=1000000006,因此使用long类型
if(n==2) return 1;
if(n==3) return 2;
while(n>4){
res*=3;
res = res%1000000007;
n=n-3;
}
return (int)(res*n%1000000007); //出循环之后,n的可能取值:n = 2,3,4
}
}
13、剑指 Offer 15. 二进制中1的个数
一、知识点
(1)位运算
- 与:&
- 或:|
- 非:~
- 异或:^
- 移位:左移n位(<<n)、右移n位(>>n)
(2)Integer类的使用
- 十进制转化为二进制:String s = Integer.toBinaryString( int i );
- 十进制转化为八进制:String s = Integer.toOctalString( int i );
- 十进制转化为十六进制:String s = Integer.toHexString( int i );
- 化为十进制:Integer.valueOf (String s, int radix),例如:int x = Integer.valueOf(“0101”,2);
- 统计二进制中1的个数:int num = Integer.bitCount( int i );
二、解题思路
思路一:移位法
- 将数字n与1进行&运算,可以判断n的末尾是否为1;
- n = n >>1 ,将n右移一位,再通过步骤一判断n的右2位是否为1;
- 依次进行判断。
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int num =0;
for(int i =0 ; i< 32 ; i++){
if((n&1)==1) num++;
n=n>>1;
}
return num;
}
}
思路二:消1法
- n&(n-1) 相当于将n最右侧的1变为0,从而消除一个1;
- 可以消几次就代表有多少个1。
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int num =0;
while(n!=0){
num++;
n=n&(n-1);
}
return num;
}
}
思路三:使用 Integer.bitCount()
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
return Integer.bitCount(n);
}
}
14、剑指 Offer 16. 数值的整数乘方
一、知识点
(1)递归
(2)Java中幂运算
- Math.pow(2,4) :2^4=16.0
二、解题思路
思路一:递归
class Solution {
public double myPow(double x, int n) {
if(n==0) return 1.0;
if(n<0) return 1/(x*myPow(x,-n-1));
else if(n%2==1) return x*myPow(x,n-1);
return myPow(x*x,n/2);
}
}
15、剑指 Offer 17. 打印从1到最大的n位数(简单)
解题思路
class Solution {
public int[] printNumbers(int n) {
int end = (int)Math.pow(10,n)-1;
int[] res = new int[end];
for(int i = 0; i< end; i++) res[i] = i+1;
return res;
}
}
16、剑指 Offer 18. 删除链表的节点(简单)
解题思路
class Solution {
public ListNode deleteNode(ListNode head, int val) {
if(head.val == val) return head.next;
ListNode pre = head, cur = head.next;
while(cur != null && cur.val != val) {
pre = cur;
cur = cur.next;
}
if(cur != null) pre.next = cur.next;
return head;
}
}
17、剑指 Offer 19. 正则表达式匹配(困难)
18、剑指 Offer 20. 表示数值的字符串
一、知识点
(1)String类的常用方法.
二、解题思路
class Solution {
public boolean isNumber(String s) {
s = s.trim();
if(s.contains("e")){
String[] arr = s.split("e",2);
if(arr.length!=2) return false;
else return (isInt(arr[0]) || isDecimal(arr[0])) && isInt(arr[1]);
}
else if(s.contains("E")){
String[] arr = s.split("E",2);
if(arr.length!=2) return false;
else return (isInt(arr[0]) || isDecimal(arr[0])) && isInt(arr[1]);
}
else if(s.contains(".")) return isDecimal(s);
return isInt(s);
}
public boolean isDecimal(String s){
int n = s.length();
String temp = "0123456789";
if(n==0) return false;
else if(!s.contains(".")) return false;
String[] arr = s.split("\\.",2);
if(arr.length==1) return isInt(arr[0]);
else if(arr.length==2){
if(arr[0].equals("")) return isIntNumber(arr[1]);
else if(arr[0].equals("+")) return isIntNumber(arr[1]);
else if(arr[0].equals("-")) return isIntNumber(arr[1]);
else if(arr[1].equals("")) return isInt(arr[0]);
else return isInt(arr[0]) && isIntNumber(arr[1]);
}
else return false;
}
public boolean isInt(String s) {
int n = s.length();
String temp = "0123456789";
if(n==0) return false;
else if(s.charAt(0)=='+' || s.charAt(0)=='-'){
if(n==1) return false;
for(int i=1; i<n; i++){
if(!temp.contains(""+s.charAt(i))) return false;
}
return true;
}
for(int i=0; i<n; i++){
if(!temp.contains(String.valueOf(s.charAt(i)))) return false;
}
return true;
}
public boolean isIntNumber(String s) {
int n = s.length();
String temp = "0123456789";
if(n==0) return false;
for(int i=0; i<n; i++){
if(!temp.contains(String.valueOf(s.charAt(i)))) return false;
}
return true;
}
}