暑假刷题总结

总结一下我做过的部分剑指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;
//	}
//    
//}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值