总结一下我做过的部分剑指offer的题
重建二叉树
// 重建二叉树
// 思路:前序遍历第一个是根节点,找到中序遍历的根节点,则找到中序遍历的左右子树,接着找到前序遍历的左右子树,用递归。
public class Solution {
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
return reBuild(pre, 0, pre.length - 1, in, 0, in.length - 1);
}
private TreeNode reBuild(int[] pre, int preStart, int preEnd, int[] in, int inStart, int inEnd) {
if (preStart > preEnd || inStart > inEnd) {//二叉树不存在的情况
return null;
}
TreeNode root = new TreeNode(pre[preStart]);//root即根节点
// 在中序遍历中找到根节点
for (int i = inStart; i < in.length; i++) {
if (root.val == in[i]) {
// 可以计算出
//中序序列的左右子树序列为:左:inStart~i - 1,右:i+1~inEnd。
// 前序序列的左右子树:左:preStart+1~preStart+i-inStart,右:preStart+i-inStart+1~preEnd
root.left = reBuild(pre, preStart + 1, preStart + i - inStart, in, inStart, i - 1);
root.right = reBuild(pre, preStart + 1 - inStart + i, preEnd, in, i + 1, inEnd);
}
}
return root;
}
}
用两个栈实现一个队列
// 用两个栈实现一个队列
// 思路:压入元素直接压入stack1
// 删除元素先查看stack2是否为空,非空则弹出;空则将stack1中元素取出,置于stack2中
import java.util.Stack;
public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void push(int node) {
stack1.push(node);
}
public int pop() {
if(stack2.isEmpty()){
while (!stack1.isEmpty()){
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
}
旋转数组的最小数字(二分法)
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length == 0){
return 0;
}
int p1 = 0;
int p2 = array.length-1;
while(p1<p2){ // 使得p1、p2交叉,p1指向最小的数
int mid = p1 + (p2-p1)/2;
if (array[mid] > array[p2]){
p1 = mid + 1;
} else if(array[mid] < array[p2]){
p2 = mid;
} else if(array[mid] == array[p2]){
p2 = p2 - 1;
}
}
return array[p1];
}
}
斐波那契数列
public class Solution {
public int Fibonacci(int n) {
int ans = 0;
if(n < 0) return -1;
if(n == 0) ans = 0;
if(n == 1) ans = 1;
if(n == 2) ans = 1;
if(n > 2) ans = Fibonacci(n-1)+Fibonacci(n-2);
return ans;
}
}
二进制中1的个数
// 二进制中1的个数
// 只用整数自己判断,如果n!=0;计算器先加1;
// 然后n=n&(n-1),就“减去”了n中的一个1,一直到减去所有的1,这个时候n==0,循环结束
public class Solution {
public int NumberOf1(int n) {
int count=0;
while(n!=0){
++count;
n=n&(n-1);
}
return count;
}
}
参考链接:n&(n-1)位运算的妙用
数值的整数次方
// 数值的整数次方
// 先考虑特殊情况,指数为0,底数为0,再分指数的正负,如为正利用递归求result,如为负先求绝对值再递归,注意返回1/result。
//public class Solution {
// public double Power(double base, int exponent) {
// if(base != 0 && exponent == 0) return 1;
// if(base == 0) return 0;
// if(base == 1) return 1;
// double result = 1.0;
// if(exponent > 0){// 指数为正数
// result = Power( base , exponent >>1);//指数除以2
// result *= result;
// if( (exponent&1) == 1){// 指数为奇数
// result *= base;
// }
// return result;
// }else if(exponent < 0){
// exponent = -exponent;
// result = Power( base , exponent);
// return 1/result;
// }
// return -1;
// }
//}
调整数组顺序使奇数位于偶数前面
//调整数组顺序使奇数位于偶数前面
//public class Solution {
// public void reOrderArray(int [] array) {
// if(array == null || array.length ==0 ||array.length == 1){
// return;
// }
// int ou = 0;
// //找到第一个偶数
// for(int i = 0;i < array.length;i++) {
// if((array[i]&1) == 0){
// ou = i;
// break;
// }
// }
// // 找下一个奇数
// for(int j = ou + 1;j < array.length;j++) {
// if((array[j]&1) == 1) {
// System.out.print(" "+j+" ");
// int temp = array[j];
// // 把ou到j-1之间的数往后移,array[ou] = array[j]
// for(int k = j;k > ou;k--) {
// array[k] = array[k - 1];
// }
// array[ou] = temp;//此时,0~ou为奇数,ou+1 ~ j为偶数
// ou++;
// }
// }
// }
//}
//上一题插入排序解法
//public class Solution {
// public void reOrderArray(int [] array) {
// int count = 0;//记录已经摆好位置的奇数的个数
// int len = array.length-1;
// for (int i = 0; i <= len; i++) {
// if(array[i]%2==1){
// int j = i;
// while(j>count){//关键在这个判断,如果奇数所在位置大于找到奇数的个数,说明中间有偶数
// int temp = array[j];
// array[j] = array[j-1];
// array[j-1] = temp;
// j--;
// }
// count++;
// }
// }
// }
//}
二叉树镜像
//二叉树镜像
//public class Solution {
// public void Mirror(TreeNode root) {
// if(root == null){
// return;
// }
// TreeNode temp = root.left;
// root.left = root.right;
// root.right = temp;
// Mirror(root.left);
// Mirror(root.right);
// }
//}
链表倒数第K个节点
//链表中倒数第k个节点
//思路:用两个指针,前指针指向k-1位置,后指针指向head,两个指针同时移动,前指针到末尾时前指针指向倒数第k个位置。注意特殊情况,head=null,和k>链表长度
//public class Solution {
// public ListNode FindKthToTail(ListNode head,int k) {
// if(head == null || k < 1) {
// return null;
// }
// ListNode preNode = head;
// ListNode inNode =head;
// //先让preNode指向k-1位置
// for(int i = 1 ;i < k;i++) {
// if(preNode.next != null) {
// preNode = preNode.next;
// }else{
// return null;
// }
// }
// while(preNode.next != null){
// preNode = preNode.next;
// inNode = inNode.next;
// }
// return inNode;
// }
//}
顺时针打印矩阵
// 顺时针打印矩阵
// 思路:一圈一圈打印矩阵,找到终止条件,分析边界情况
//import java.util.ArrayList;
//public class Solution {
// public ArrayList<Integer> printMatrix(int [][] matrix) {
// ArrayList<Integer> arr = new ArrayList<>();
// ArrayList<Integer> arrTemp = new ArrayList<>();
// if(matrix == null){
// return null;
// }
// int rows = matrix.length;
// int columns = matrix[0].length;
// int start = 0;
// // 用一个循环每次打印一个圈
// // 终止条件:columns > (start * 2) && rows > (start * 2) 《===注意分析终止条件
// while(columns > (start * 2) && rows > (start * 2)){
// arrTemp = printMatrixInCircle(matrix , rows , columns , start);
// arr.addAll(arrTemp);
// start++;
// }
// return arr;
// }
// // 按圈打印矩阵,注意分析边界条件
// private ArrayList<Integer> printMatrixInCircle(int [][] matrix , int rows , int columns , int start) {
// ArrayList<Integer> arr = new ArrayList<>();
// int endX = columns - 1 - start;
// int endY = rows - 1 -start;
// // 从左到右打印一行
// for(int i = start;i <= endX;i++) {
// arr.add(matrix[start][i]);
// }
// // 从上到下打印一列
// if(start < endY) {
// for(int i = start + 1;i <= endY;i++) {
// arr.add(matrix[i][endX]);
// }
// }
// // 从右到左打印一行
// if(start < endX && start < endY) {
// for(int i = endX - 1;i >= start;i--) {
// arr.add(matrix[endY][i]);
// }
// }
// // 从下到上打印一列
// if(start < endY - 1 &&start < endX) {
// for(int i = endY - 1;i > start;i--) {
// arr.add(matrix[i][start]);
// }
// }
// return arr;
// }
//}
包含min函数的栈
// 包含min函数的栈
// 用两个栈,一个栈保存数据,另一个栈保存最小值
//import java.util.Stack;
//public class Solution {
// Stack<Integer> data_stack = new Stack<>();
// Stack<Integer> min_stack = new Stack<>();
//
// public void push(int node) {
// data_stack.push(node);
// if(min_stack.size() == 0 || node < min_stack.peek()) {
// min_stack.push(node);
// }else {
// min_stack.push(min_stack.peek());
// }
// }
//
// public void pop() {
// if(data_stack.size() > 0) {
// data_stack.pop();
// min_stack.pop();
// }
// }
//
// public int top() {
// if(data_stack.size() > 0) {
// return data_stack.peek();
// }
// return 0;
// }
//
// public int min() {
// if(min_stack.size() > 0) {
// return min_stack.peek();
// }
// return 0;
// }
//}
链表反转
// 反转链表
// 利用三个指针,pre,now,next
//public class Solution {
// public ListNode ReverseList(ListNode head) {
// if(head == null) {
// return null;
// }
// ListNode now = head;// 当前节点
// ListNode pre = null;// 前一个节点
// ListNode temp = null;// 辅助节点
// while(now != null) {
// ListNode next = now.next;// 下一个节点
// if(next == null) {
// temp = now;
// }
// now.next = pre;//当前节点的指针指向前一个节点=====》反转
// pre = now;// 前一个节点指向当前节点 =====》pre指针后移
// now = next; // 当前节点指向下一个节点=====》now指针后移
// }
// return temp;// 辅助节点存储尾节点
// }
//}
合并两个排好序的链表
// 合并两个排序的链表
// 可以用递归
//public class Solution {
// public ListNode Merge(ListNode list1,ListNode list2) {
// if(list1 == null) return list2;
// if(list2 == null) return list1;
// ListNode newNode = null;
// if(list1.val < list2.val){
// newNode = list1;
// list1.next = Merge(list1.next,list2);
// }else {
// newNode = list2;
// list2.next = Merge(list1,list2.next);
// }
// return newNode;
// }
//}
树的子结构
// 树的子结构
// 第一步:用递归遍历A树,找到与B树相同的根节点
// 第二步:用递归比较左右子树
//public class Solution {
// public boolean HasSubtree(TreeNode root1,TreeNode root2) {
// if(root2 == null) return false;
// if(root1 == null && root2 != null) return false;
// boolean flag = false;
// // 找到相同根节点
// if(root1.val == root2.val) {
// flag = isSubTree(root1,root2);//第二步
// }
// if(!flag){ // 当前节点不相等或者左右子树不等
// flag = HasSubtree(root1.left,root2);// 比较左节点
// if(!flag) flag = HasSubtree(root1.right,root2);// 比较右节点
// }
// return flag;
// }
// private boolean isSubTree(TreeNode root1,TreeNode root2){
// if(root2 == null) return true;
// if(root1 == null && root2 != null) return false;
// if(root1.val == root2.val) {
// return isSubTree(root1.left,root2.left)&&isSubTree(root1.right, root2.right);
// }else{
// return false;
// }
// }
//}
栈的压入弹出序列
// 栈的压入弹出序列
// 思路:借助一个辅助栈
// 首先,分析边界情况:都为空,长度不相等
// 其次,按照入栈序列压入辅助栈,如果辅助栈栈顶元素等于出栈栈顶元素,辅助栈出栈,直到入栈完毕
// 根据辅助栈是否为空判断true or false
//import java.util.Stack;
//public class Solution {
// public boolean IsPopOrder(int [] pushA,int [] popA) {
// if(pushA.length == 0||popA.length == 0||pushA.length != popA.length) {
// return false;
// }
// Stack<Integer> stack = new Stack<>();
// int j = 0;
// for(int i = 0;i < pushA.length;i++) {
// stack.push(pushA[i]);
// while(!stack.isEmpty()&&stack.peek() == popA[j]){
// stack.pop();
// j++;
// }
// }
// return stack.isEmpty();
// }
//}
从上到下打印二叉树
// 从上到下打印二叉树
// 思路:观察规律可以用一个队列来存储,如果该节点有子节点,则把子节点加入到队列中,再取出队列头部节点重复判断是否有子节点,终止条件是队列为空。
//import java.util.ArrayList;
//import java.util.LinkedList;
//import java.util.Queue;;
//public class Solution {
// public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
// ArrayList<Integer> list = new ArrayList<>();
// Queue<TreeNode> queue = new LinkedList<TreeNode>();
// if(root == null) return list;
// queue.add(root);// 先把根节点加入到队列中
// while(queue.size() > 0) {
// // 取出队列的头部节点
// TreeNode node = queue.poll();
// // 加入到数组中
// list.add(node.val);
// // 对左右子节点判断
// if(node.left != null) {
// queue.add(node.left);
// }
// if(node.right != null) {
// queue.add(node.right);
// }
// }
// return list;
// }
//}
数组中重复的数字
// 数组中重复的数字
// 思路:首先,检查无效测试用例;用一个循环遍历数组,再内嵌一个while循环,比较当前数值和下标i是否相等,如果相等则返回true,传值给duplication;如果不等则交换下标分别为i和numbers[i]的数。
//public class Solution {
// public boolean duplicate(int numbers[],int length,int [] duplication) {
// if(numbers == null || length <= 0) return false;// 数组为空,或者长度小于0
// for(int i = 0;i < length;i++) {
// if(numbers[i]<0||numbers[i]>length - 1)// 数字超过规定范围
// return false;
// }
// for(int i = 0;i < length;i++) {
// while(numbers[i] != i) { // 循环终止条件:当numbers[i]==i时
// int temp = numbers[i];
// if(numbers[i] == numbers[temp]){// 如果i和temp数字相同,则找到重复数字
// duplication[0] = numbers[i];
// return true;
// }
// // 否则,交换下标i和temp位置的数
// numbers[i] = numbers[temp];
// numbers[temp] = temp;
// }
// }
// return false;
// }
//}
二叉搜索树的后序遍历
// 二叉搜索树的后序遍历
// 思路:首先找到左右子树,判断是否满足二叉搜索树的定义,再用递归判断左右子树是否为二叉搜索树的定义
//public class Solution {
// public boolean VerifySquenceOfBST(int [] sequence) {
// if(sequence.length == 0) return false;
// int len = sequence.length;
// int root = sequence[len - 1];
// int i = 0;
// // 找到根节点对应的左子树
// for(;i < len -1;i++) {
// if(sequence[i] > root){
// break;
// }
// }
// // 检查右子树是否满足二叉搜索树的定义
// int j = i;
// for(;j < len -1;j++) {
// if(sequence[j] < root) {// 不满足则返回false
// return false;
// }
// }
// // 递归
// // 判断左子树是否为二叉搜索树(i=0~i-1)
// boolean isLeft = true;
// if(i>0){
// int[] left = new int[i];
// for(int k =0;k < i;k++) {
// left[k] = sequence[k];
// }
// isLeft = VerifySquenceOfBST(left);
// }
// // 判断右子树是否为二叉搜索树(j=i~len-1)
// boolean isRight = true;
// if(i < len - 1) {
// int[] right = new int[len - i - 1];
// for(int k = i , l = 0;k < len - 1 ;k++,l++) {
// right[l] = sequence[k];
// }
// isRight = VerifySquenceOfBST(right);
// }
// return(isLeft&&isRight);
// }
//}
二叉树中中和为某一值的路径
// 二叉树中中和为某一值的路径(有点难)
// 思路: 首先,就是要把当前结点(首先是根结点)添加到路径里,同时target 减去当前结点的值;
// 然后,如果当前结点为叶节点并且和也达到给定值,就把这个路径添加到列表,否则就一直遍历下去;
// 最后,遍历到叶节点之后,返回上层结点之前,一定要把最后一个结点从路径中删除;
// 把符合条件的路径添加到列表中的时候,因为add添加的是引用,如果不是每次都new一个path的话,最终list保存到的只是最后一个path(可以看一下ArrayList的源码)
//import java.util.ArrayList;
//public class Solution {
// public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
// ArrayList<ArrayList<Integer>> list = new ArrayList<>();
// ArrayList<Integer> path = new ArrayList<>();
//
// return FindPath(root,target,path,list);
// }
// /**
// *
// * @param root 根节点
// * @param target 整数
// * @param path 路径
// * @param list 返回值
// * @return
// */
// private ArrayList<ArrayList<Integer>> FindPath(TreeNode root, int target, ArrayList<Integer> path,
// ArrayList<ArrayList<Integer>> list) {
// if(root == null) return list;
// // 每访问到一个节点时,把节点加到路径中,同时调整target的值
// path.add(root.val);
// target -= root.val;
// // 已到叶节点并且和为target,则把当前路径添加到输出列表里
// // 因为add添加的是引用,如果不new一个的话,最终list保存到的只是最后一个path
// if(target == 0 && root.left == null && root.right == null) { // 当前路径和是指定值且当前节点是叶子节点
// list.add(new ArrayList<Integer>(path));
// }
// // 否则继续遍历
// FindPath(root.left, target, path , list);
// FindPath(root.right, target, path , list);
// // 已到叶节点之后会跳过两个递归函数到这里,此时要把最后一个结点从路径中删除,才能返回上层结点
// path.remove(path.size() - 1);
// return list;
// }
//}
复杂链表的复制
//class RandomListNode {
// int label;
// RandomListNode next = null;
// RandomListNode random = null;
//
// RandomListNode(int label) {
// this.label = label;
// }
//}
//public class Solution {
// //1.加入copy结点
// public void copyNodes(RandomListNode pHead){
// RandomListNode walkNode=pHead;
// while(walkNode!=null){
// RandomListNode cloneNode=new RandomListNode(walkNode.label);
// cloneNode.next=walkNode.next;
// walkNode.next=cloneNode;
// walkNode=cloneNode.next;
// }
// }
// //2.为新copy结点的random域指定值
// public void initRandom(RandomListNode pHead){
// RandomListNode walkNode=pHead;
// RandomListNode cwalkNode=pHead;
// while(walkNode!=null){
// cwalkNode=walkNode.next;
// if(walkNode.random!=null){
// cwalkNode.random=walkNode.random.next;
// }
// walkNode=cwalkNode.next;
// }
// }
// //3.将链表和其copy版本分为两个链表
// public RandomListNode split2list(RandomListNode pHead){
// RandomListNode cpHead=pHead.next;
// RandomListNode walkNode=pHead;
// RandomListNode cwalkNode=cpHead;
// while(walkNode!=null){
// walkNode.next=cwalkNode.next;
// walkNode=walkNode.next;
// if(walkNode==null){
// cwalkNode.next=null;
// }
// else{
// cwalkNode.next=walkNode.next;
// cwalkNode=cwalkNode.next;
// }
// }
// return cpHead;
// }
// public RandomListNode Clone(RandomListNode pHead)
// {
// if(pHead==null){
// return null;
// }
// copyNodes(pHead);
// initRandom(pHead);
// return split2list(pHead);
// }
//
//}
数组中出现次数超过一半的数字
// 数组中出现次数超过一半的数字
// 遍历数组的时候可以保存两个值:数组中的一个数temp和出现的次数counter
//public class Solution {
// public int MoreThanHalfNum_Solution(int [] array) {
// int temp = array[0];
// int counter = 1;// 计数器
// for(int i=1; i<array.length; i++){
// if(array[i] == temp) // 相等则计数器加一
// counter++;
// else{ // 不等则计数器减一
// counter--;
// }
// if(counter == 0){ // 计数器为0时,替换temp,counter置一
// temp = array[i];
// counter = 1;
// }
// }
// // 保证找出来的数counter大于一半,否则返回0
// counter = 0;
// for(int i=0; i<array.length; i++){// 找到数字res的次数
// if(array[i] == temp)
// counter++;
// }
// return counter > array.length/2 ? temp : 0;
// }
//}
最小的k个数
// 最小的k个数
//import java.util.ArrayList;
//public class Solution {
// public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
// ArrayList<Integer> result = new ArrayList<>();
// if(k <= 0 || input.length == 0 || input.length < k) return result;
// int start = 0;
// int end = input.length - 1;
// int index = Partition(input,start,end);
// while(index != k - 1) {
// if(index > k - 1) {
// end = index - 1;
// index = Partition(input, start, end);
// }else {
// start = index + 1;
// index = Partition(input, start, end);
// }
// }
// for(int i = 0;i < k;i++) {
// result.add(input[i]);
// }
// return result;
// }
//
// private int Partition(int[] input, int start, int end) {
// // TODO Auto-generated method stub
// int pivot = input[start];
// while(start < end) {
// while(start < end && input[end] >= pivot)
// end--;
// input[start] = input[end];
// while(start < end && input[start] <= pivot)
// start++;
// input[end] = input[start];
// }
// input[end] = pivot;
// return end;
// }
//
//}