陆续刷了好久,算是刷完了《剑指offer》,以下全部AC代码,不一定性能最优,如有错误或更好解答,请留言区指出,大家共同交流,谢谢~
- 《剑指offer》全部题目-含Java实现(二)
1.二维数组中的查找
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
public class Solution { public boolean Find(int target, int [][] array) { if(array == null||array.length==0) return false; int rowIdx = 0,colIdx = array[0].length-1; while(rowIdx=0){ if(array[rowIdx][colIdx] == target) return true; else if(target>array[rowIdx][colIdx]) rowIdx++; else if(target
2.替换空格
请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
public class Solution { public String replaceSpace(StringBuffer str) { StringBuilder sb = new StringBuilder(); for(int i = 0;i
3.从尾到头打印链表
输入一个链表,从尾到头打印链表每个节点的值。
/*** public class ListNode {* int val;* ListNode next = null;** ListNode(int val) {* this.val = val;* }* }**/import java.util.ArrayList;import java.util.Stack;public class Solution { public ArrayList printListFromTailToHead(ListNode listNode) { ArrayList result = new ArrayList<>(); Stack stack = new Stack<>(); if(listNode == null) return result; while(listNode != null){ stack.push(listNode.val); listNode = listNode.next; } while(!stack.isEmpty()) result.add(stack.pop()); return result; }}
==4.重建二叉树==
使用递归
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
/** * Definition for binary tree * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */public class Solution { public TreeNode reConstructBinaryTree(int[] pre, int[] in) { if (pre == null || in == null || pre.length != in.length||pre.length == 0) return null; return reConstructBinaryTreeCore(pre, 0, pre.length - 1, in, 0, in.length - 1); } public TreeNode reConstructBinaryTreeCore(int[] pre, int preStartIdx, int preEndIdx, int[] in, int inStartIdx, int inEndIdx) throws Exception{ TreeNode node = new TreeNode(pre[preStartIdx]); if (preStartIdx == preEndIdx) if (inStartIdx != inEndIdx || pre[preStartIdx] != in[inStartIdx]) throw new Exception("Invalid input."); int i = 0; while (pre[preStartIdx] != in[inStartIdx + i]) i++; if (i == 0)//证明没有左子树 node.left = null; else node.left = reConstructBinaryTreeCore(pre, preStartIdx + 1, preStartIdx + i, in, inStartIdx, inStartIdx + i - 1); if (inStartIdx + i == inEndIdx)//证明没有右子树 node.right = null; else node.right = reConstructBinaryTreeCore(pre, preStartIdx + i + 1, preEndIdx, in, inStartIdx + i + 1, inEndIdx); return node; }}
5.用两个栈实现队列
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
import java.util.Stack;public class Solution { Stack stack1 = new Stack(); Stack stack2 = new Stack(); public void push(int node) { stack1.push(node); } public int pop() throws Exception { if(stack1.isEmpty()&&stack2.isEmpty()) throw new Exception("Queue is empty."); if(!stack2.isEmpty()) return stack2.pop(); while(!stack1.isEmpty()) stack2.push(stack1.pop()); return stack2.pop(); }}
==6.旋转数组的最小数字==
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
public class Solution { public int minNumberInRotateArray(int [] array) { if(array == null||array.length == 0)return 0; int idx1 = 0,idx2 = array.length-1; //如果不能进入while循环,则证明第一个元素小于最后一个元素,而且数组为非递减排序,最小值即为首位。 while(array[idx1]>=array[idx2]){ //第一个指针指向前半段递增序列的末尾,第二个指针指向后半段递增序列的首位。 if(idx2-idx1==1)return array[idx2]; //二分法查找临界点 int mid = (idx1+idx2)/2; //考虑特例:{1,0,1,1,1} if(array[idx1] == array[idx2]&& array[mid] == array[idx1]){ for(int i = idx1;i<=idx2;i++) if(array[i]=array[idx1]) idx1 = mid; else if(array[mid]<=array[idx2]) idx2 = mid; } //此时数组为递增排列,第一个元素最小 return array[0]; }}
7.斐波那契数列
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。
n<=39
public class Solution { public int Fibonacci(int n) { if(n<1) return 0; int[] fibonacci = new int[2]; fibonacci[0] = 1; fibonacci[1] = 1; n-=2; while(n>0){ int temp = fibonacci[0]+fibonacci[1]; fibonacci[0] = fibonacci[1]; fibonacci[1] = temp; n--; } return fibonacci[1]; }}
8.跳台阶(动态规划)
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
public class Solution { public int JumpFloor(int target) { if(target < 1) return 0; int[] DP = new int[3]; DP[0] = 1; DP[1] = 2; DP[2] = DP[0]+DP[1]; if(target<=3) return DP[target-1]; for(int i =4;i<=target;i++){ DP[0] = DP[1]; DP[1] = DP[2]; DP[2] = DP[0]+DP[1]; } return DP[2]; }}
9.(变态版)跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
public class Solution { public int JumpFloorII(int target) { if(target<=0) return -1; //if(target == 1) return 1; return (int)Math.pow(2,target - 1); // return 2*JumpFloorII(target-1); }}
10.矩形覆盖
我们可以用2×1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2×1的小矩形无重叠地覆盖一个2×n的大矩形,总共有多少种方法?
public class Solution { public int RectCover(int target) { if(target<1) return 0; int[] DP = new int[3]; DP[0] = 1; DP[1] = 2; DP[2] = DP[1]+DP[0]; if(target<4) return DP[target-1]; for(int i = 4;i<=target;i++){ int temp = DP[1]+DP[2]; DP[0] = DP[1]; DP[1] = DP[2]; DP[2] = temp; } return DP[2]; }}
11.二进制中1的个数
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
public class Solution { public int NumberOf1(int n) { int count = 0; while(n!=0){ count+=n&1; n=n>>>1; // >>>运算符,使符号位也跟着右移 } return count; }}
12.数值的整数次方
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
public class Solution { public double Power(double base, int exponent) { if(base == 0 && exponent < 0)//输入不合法 return 0.0; if(exponent < 0) return 1/PowerWithPositive(base,-1*exponent); else return PowerWithPositive(base,exponent); } public double PowerWithPositive(double base,int exponent){ if(exponent == 0) return 1; if(exponent == 1) return base; double result = PowerWithPositive(base,exponent >> 1); result *= result; if((exponent & 1) == 1) result *= base; return result; }}
13.调整数组顺序使奇数位于偶数前面
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
import java.util.Stack;public class Solution { public void reOrderArray(int [] array) { if(array == null||array.length == 0) return; Stack odd = new Stack<>(); Stack even = new Stack<>(); for(int i = 0;i
14.链表中倒数第K个结点
输入一个链表,输出该链表中倒数第k个结点。(能用指针尽量不要使用辅助栈)
方法一:使用指针
/*public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; }}*/import java.util.Stack;public class Solution { public ListNode FindKthToTail(ListNode head,int k) { if(head == null || k<=0) return null; ListNode node1 = head,node2 = head; for(int i=1;i
方法二:使用辅助栈
/*public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; }}*/import java.util.Stack;public class Solution { public ListNode FindKthToTail(ListNode head,int k) { Stack stack = new Stack<>(); ListNode node = head; while(node!=null){ stack.push(node); node = node.next; } for(int i =0;i
15.反转链表
输入一个链表,反转链表后,输出新链表的表头。
/*public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; }}*/public class Solution { public ListNode ReverseList(ListNode head) { if(head == null) return null; ListNode node1 = null,node2 = head,node3 = head.next; while(node3!=null){ node2.next = node1; node1 = node2; node2 = node3; node3 = node3.next; } node2.next = node1; return node2; }}
15.反转链表
输入一个链表,反转链表后,输出链表的所有元素。
解法一:(使用栈)
/*public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; }}*/import java.util.Stack;public class Solution { public ListNode ReverseList(ListNode head) { Stack stack = new Stack<>(); if(head == null) return null; while(head != null){ stack.push(head); head = head.next; } head = stack.pop(); ListNode temp = head; while(!stack.empty()){ temp.next = stack.pop(); temp = temp.next; } temp.next = null;//一定要注意这里的这行代码 //一定要将链表末位next置为null return head; }}
解法二:
public class Solution{ public ListNode ReverseList(ListNode head){ ListNode reversedListHead; ListNode pre = null; ListNode node = null; ListNode next = null; if(head == null) return null; node = head; while(true){ next = node.next; node.next = pre; pre = node; if(next == null){ reversedListHead = node; break; } node = next; } return reversedListHead; }}
16.合并两个排序的链表
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
解法一:
public class Solution { public ListNode Merge(ListNode list1,ListNode list2) { //if(list1 == null && list2 == null) return null; //这行代码可以不要,因为当list1 == null return list2也等于null if(list1 == null) return list2; if(list2 == null) return list1; ListNode head,node; if(list1.val <= list2.val){ node = list1; head = node; list1 = list1.next; }else{ node = list2; head = node; list2 = list2.next; } while(list1 != null&&list2 != null){ if(list1.val<=list2.val){ node.next = list1; list1 = list1.next; node = node.next; }else{ node.next = list2; list2 = list2.next; node = node.next; } } while(list1 != null){ node.next = list1; list1 = list1.next; node = node.next; } while(list2 != null){ node.next = list2; list2 = list2.next; node = node.next; } return head; }}
解法二:(使用递归)
public class Solution { public ListNode Merge(ListNode list1,ListNode list2) { if(list1 == null) return list2; if(list2 == null) return list1; ListNode MergedHead = null; if(list1.val <= list2.val){ MergedHead = list1; MergedHead.next = Merge(list1.next,list2); }else{ MergedHead = list2; MergedHead.next = Merge(list1,list2.next); } return MergedHead; }}
17.树的子结构
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
/**public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; }}*/public class Solution { public boolean HasSubtree(TreeNode root1,TreeNode root2) { if(root1==null||root2==null) return false; boolean result = false; if(root1.val == root2.val){ result = isEqualTree(root1,root2); } if(!result) result = HasSubtree(root1.left,root2); if(!result) result = HasSubtree(root1.right,root2); return result; } public boolean isEqualTree(TreeNode tree1,TreeNode tree2){ //注意此处,只需判断tree2 == null即可返回true; //因为tree2为子树,此时tree1可以不为null,即tree1不为叶节点 if(tree2 == null) return true; if(tree1 == null) return false; if(tree1.val == tree2.val){ return isEqualTree(tree1.left,tree2.left) && isEqualTree(tree1.right,tree2.right); } return false; }}
18.二叉树的镜像
操作给定的二叉树,将其变换为源二叉树的镜像。
/**public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; }}*/public class Solution { public void Mirror(TreeNode root) { if(root != null){ TreeNode temp = root.left; root.left = root.right; root.right = temp; if(root.left!=null) Mirror(root.left); if(root.right!=null) Mirror(root.right); } }}
==19.顺时针打印矩阵(这道题有难度)==
==见书P161==
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
知识点:
关于值传递和引用传递可以得出这样的结论:
基本数据类型传值,对形参的修改不会影响实参;引用类型传引用,形参和实参指向同一个内存地址(同一个对象),所以对参数的修改会影响到实际的对象;String, Integer, Double等immutable的类型特殊处理,可以理解为传值,最后的操作不会修改实参对象。
解法一:
import java.util.ArrayList;public class Solution { public ArrayList printMatrix(int [][] matrix) { if(matrix == null) return null; ArrayList result = new ArrayList<>(); int start = 0; while(start*2 result){ int endX = matrix[0].length - 1 - start; int endY = matrix.length - 1 - start; for(int i = start;i <= endX;i++){ result.add(matrix[start][i]); } if(start < endY){ for(int i = start +1;i <= endY;i++) result.add(matrix[i][endX]); } if(start=start;i--) result.add(matrix[endY][i]); if(startstart;i--) result.add(matrix[i][start]); }}
解法二:
import java.util.ArrayList;public class Solution { public ArrayList printMatrix(int [][] matrix) { if(matrix == null) return null; ArrayList result = new ArrayList<>(); int h = matrix.length,w = matrix[0].length,round = 0; while(result.size()=round) result.add(matrix[r][c--]); c++; r--; while(r>round) result.add(matrix[r--][c]); round++; } return result; }}
20 包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。
import java.util.Stack;public class Solution { Stack stack = new Stack(); Stack minStack = new Stack(); int min; public void push(int node) { stack.push(node); if(minStack.empty()) min = node; else min = Math.min(minStack.peek(),node); minStack.push(min); } public int pop() { minStack.pop(); return stack.pop(); } public int top() { return stack.peek(); } public int min() { return minStack.peek(); }}
21.栈的压入、弹出序列
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
【解题思路】:设计一个辅助栈,如果下一个弹出的数字是辅助栈的栈顶,则弹出,如果不是栈顶,则继续将压入序列压入辅助栈,直到把下一个需要弹出的数字压入栈顶为止;如果所有数字都压入辅助站,栈顶仍然不是欲弹出的数字,则该序列不可能是一个弹出序列。
==注意:当stack为空的时候,调用peek()方法会抛出异常==
import java.util.Stack;public class Solution { public boolean IsPopOrder(int [] pushA,int [] popA) { if(pushA == null||popA == null||pushA.length!=popA.length) return false; Stack stack = new Stack<>(); int j = 0; for(int i = 0 ;i
22.从上往下打印二叉树
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
Java知识点:
返回长度:String.length();String字符串用length()方法会返回其长度。Array.length;数组有length属性,直接数组名点length就可以取到。ArrayList.size()方法的会返回其长度。ArrayList 操作:get(),add(),remove()You need to use the get() method to get the element at a particular index from an ArrayList. You can't use [] to get the element at a particular index, in an arraylist. Its possible only for arrays and your files is not an array, but an ArrayList.
==一定要注意,Java中Queue为接口,如果使用队列需要使用LinkedList(双向队列)、PriorityQueue(优先队列)==
解法一:
import java.util.ArrayList;import java.util.LinkedList;/** * public class TreeNode { * int val = 0; * TreeNode left = null; * TreeNode right = null; * * public TreeNode(int val) { * this.val = val; * } * } */public class Solution { public ArrayList PrintFromTopToBottom( TreeNode root ) { ArrayList result = new ArrayList<>(); if ( root == null ) return(result); LinkedList queue = new LinkedList<>(); result.add( root.val ); if ( root.left != null ) queue.offer( root.left ); if ( root.right != null ) queue.offer( root.right ); while ( !queue.isEmpty() ) { TreeNode node = queue.poll(); result.add( node.val ); if ( node.left != null ) queue.offer( node.left ); if ( node.right != null ) queue.offer( node.right ); } return(result); }}
解法二:
/**public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; }}*/import java.util.ArrayList;/**用arraylist模拟一个队列来存储相应的TreeNode*/public class Solution { ArrayList result = new ArrayList<>(); ArrayList temp = new ArrayList<>(); public ArrayList PrintFromTopToBottom(TreeNode root) { if(root == null) return result; temp.add(root); while(temp.size() != 0){ TreeNode node = temp.remove(0); result.add(node.val); if(node.left!=null) temp.add(node.left); if(node.right!=null) temp.add(node.right); } return result; }}
23.二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出True,否则输出False。假设输入的数组的任意两个数字都互不相同。
public class Solution { public boolean VerifySquenceOfBST(int [] sequence) { if(sequence == null || sequence.length == 0) return false; int start = 0,end = sequence.length-1; return isSearchTree(sequence,start,end); } public boolean isSearchTree(int [] sequence,int start,int end){ if(end==start) return true; int root = sequence[end]; int index = end; for(int i = start;i root){ index = i; break; } } for(int i = index;i
24.二叉树中和为某一值的路径
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
【解题思路】:因为根结点和叶子结点一定在路径中,而且路径开始一定是跟结点,使用前序遍历遍历二叉树,每经过一个结点减小target的值,直至找到使target=0的叶子结点,即为路径,每次回退,需要删除路径中最后一个结点。
import java.util.ArrayList;/**public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; }}*/public class Solution { private ArrayList> allPath = new ArrayList<>(); private ArrayList path = new ArrayList<>(); public ArrayList> FindPath(TreeNode root,int target) { if(root == null) return allPath; target -= root.val; path.add(root.val); if(target == 0&& root.left == null&&root.right == null) allPath.add(new ArrayList(path)); else{ FindPath(root.left,target); FindPath(root.right,target); } path.remove(path.size()-1); return allPath; }}
25.复杂链表的复制
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
/*public class RandomListNode { int label; RandomListNode next = null; RandomListNode random = null; RandomListNode(int label) { this.label = label; }}*/public class Solution { public RandomListNode Clone(RandomListNode pHead) { //一定注意考虑输入为空链表的情况 if(pHead == null) return null; //第一步:克隆每个结点的值和next,并且将新节点放置在对应旧结点之后 RandomListNode node = pHead; while(node != null){ RandomListNode cloneNode = new RandomListNode(node.label); //cloneNode.label = node.label; cloneNode.next = node.next; node.next = cloneNode; node = cloneNode.next; } //第二步:克隆每个随机指针 node = pHead; while(node != null){ RandomListNode cloneNode = node.next; if(node.random != null) cloneNode.random = node.random.next; node = cloneNode.next; } //第三步:拆分拼接的链表 node = pHead; RandomListNode cloneHead = pHead.next; while(node != null){ RandomListNode cloneNode = node.next; node.next = cloneNode.next; node = node.next; if(node != null) cloneNode.next = node.next; else cloneNode.next = null; } return cloneHead; } }
出处:http://www.guoyaohua.com