题顺序按照剑指Offer,实际运行在牛客网。讲解见《剑指Offer》
- 第三题
题目:找出数组中重复的数字
代码实现
- 剑指Offer思路
public class Solution {
public boolean duplicate(int numbers[],int length,int [] duplication) {
int res = -1;
for(int i=0;i<length;i++) {
int temp = numbers[i];
int index = i;
while(numbers[index]!=index) {
// 把当前值/所对应的下表标/所对应的元素 /与当前值交换位置
if(numbers[index]==numbers[numbers[index]]) { //如果当前值与 以当前值作为下标的值相同,则找到重复
res = numbers[index];
duplication[0] = res;
return res != -1;
}
temp = numbers[index];
numbers[index] = numbers[temp];
numbers[temp]=temp;
}
}
return res != -1;
}
}
- 使用Map(个人理解)
public class Solution {
public boolean duplicate(int numbers[],int length,int [] duplication) {
if(length==0) {
return false;
}else {
TreeMap<Integer,Integer> map = new TreeMap<>();
for(int num:numbers) {
if(map.get(num)!=null) {
map.put(num, map.get(num)+1);
}else {
map.put(num, 1);
}
}
Random rand = new Random();
ArrayList<Integer> list = new ArrayList<>();
for(int key:map.keySet()) {
if(map.get(key)>1) {
list.add(key);
}
}
if(list.size()!=0) {
int randIndex = rand.nextInt(list.size());
duplication[0] = list.get(randIndex);
return true;
}else {
return false;
}
}
}
- 第四题
题目:二维数组中的查找
代码实现
- 剑指Offer思路
public class Solution {
public boolean Find(int target, int [][] array) {
if(array==null || array[0].length==0 ) {
return false;
}
int com = 0;
int row = array.length-1;
while(com<array.length && row>=0) {
if(target == array[com][row]) {
return true;
}
if(target<array[com][row]) { //删除列
row --;
}else if(target>array[com][row]) { //删除行
com ++;
}
}
return false;
}
}
- 按照每一行(列)采用二分查找(个人理解)
public class Solution {
public boolean Find(int target, int [][] array) {
int size = array.length;
boolean flag;
for(int i=0;i<size;i++) {
flag = binarySearch(array[i],target);
if(flag==true) {
return true;
}
}
return false;
}
public boolean binarySearch(int[] arr,int target) {
int min = 0;
int max = arr.length-1;
while(max>=min) {
int mid = (min+max)/2;
if(arr[mid]<target) {
min = mid+1;
}else if(arr[mid]>target) {
max = mid -1;
}else {
return true;
}
}
return false;
}
}
- 第五题
题目:替换空格
代码实现
- 剑指Offer思路
public class Solution {
public String replaceSpace(StringBuffer str) {
int count=0;
for(int i=0;i<str.length();i++) {
if(str.charAt(i)==' ') {
count++;
}
}
char[] newChar = new char[str.length()+2*count];
for(int i=str.length()-1,j=newChar.length-1;i>=0 && j>=0;i--,j--) {
if(str.charAt(i)!=' ') {
newChar[j] = str.charAt(i);
}else {
newChar[j--]='0';
newChar[j--]='2';
newChar[j]='%';
}
}
String L="";
for(int i=0;i<newChar.length;i++) {
L = L+newChar[i];
}
return L;
}
}
- 使用StringBuilder
public class Solution {
public String replaceSpace(StringBuffer str) {
StringBuilder res = new StringBuilder();
for(int i=0;i<str.length();i++) {
char cha = str.charAt(i);
if(cha != ' ') {
res.append(cha);
}else {
res.append("%20");
}
}
return res.toString();
}
}
- 第六题
题目:从尾到头打印链表
代码实现
- 利用栈
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
public static class ListNode{
int val;
ListNode next = null;
public ListNode(int val) {
this.val = val;
}
}
public static ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> list = new ArrayList<>();
Stack<Integer> stack = new Stack<Integer>();
while(listNode!=null) {
stack.add(listNode.val);
listNode = listNode.next;
}
while(!stack.isEmpty()) {
list.add(stack.pop());
}
return list;
}
//测试用例
public static void main(String[] args) {
ListNode node = new ListNode(0);
ListNode tnode = node;
for(int i=1;i<10;i++) {
node.next = new ListNode(i);
node = node.next;
}
ArrayList<Integer> list = printListFromTailToHead(tnode);
System.out.println(list);
}
}
- 利用递归实现
import java.util.ArrayList;
public class Solution {
public static class ListNode{
int val;
ListNode next = null;
public ListNode(int val) {
this.val = val;
}
}
public static ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
if(listNode==null) {
return new ArrayList<Integer>();
}
ArrayList<Integer> list = new ArrayList<>();
ListNode root = reverseNode(listNode);
while(root!=null) {
list.add(root.val);
root = root.next;
}
return list;
}
public static ListNode reverseNode(ListNode listNode) {
ListNode root = new ListNode(listNode.val);
root = reverseNode(root,listNode.next);
return root;
}
private static ListNode reverseNode(ListNode root,ListNode listNode) {
if(listNode==null) {
return root;
}
ListNode rightNode = listNode.next;
listNode.next = root;
root = listNode;
return reverseNode(root,rightNode);
}
//测试用例
public static void main(String[] args) {
ListNode node = new ListNode(0);
ListNode tnode = node;
for(int i=1;i<10;i++) {
node.next = new ListNode(i);
node = node.next;
}
ArrayList<Integer> list = printListFromTailToHead(tnode);
System.out.println(list);
}
}
public class Solution {
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int x) {
val = x;
}
}
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
TreeNode root=reConstructBinaryTree(pre,0,pre.length-1,in,0,in.length-1);
return root;
}
//前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
private TreeNode reConstructBinaryTree(int [] pre,int startPre,int endPre,int [] in,int startIn,int endIn) {
if(startPre>endPre||startIn>endIn)
return null;
TreeNode root=new TreeNode(pre[startPre]);//构建当前根节点
for(int i=startIn;i<=endIn;i++)
if(in[i]==pre[startPre]){
// (i-startIn)表示当满足in[i]==pre[startPre]条件时,数据发生偏移的位数
root.left=reConstructBinaryTree(pre,startPre+1,startPre+(i-startIn),in,startIn,i-1);
root.right=reConstructBinaryTree(pre,(i-startIn)+startPre+1,endPre,in,i+1,endIn);
}
return root;
}
}
- 第八题
题目:二叉树的下一个节点
思路分析:
代码实现:
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode)
{
TreeLinkNode resNode;
if (pNode == null)
return pNode;
if(pNode.right!=null) {
resNode = findMin(pNode.right);
return resNode;
}
if(pNode.right==null) {
if(pNode.next!=null && pNode.next.left == pNode) {
resNode = pNode.next;
return resNode;
}
if(pNode.next!=null && pNode.next.right == pNode) {
while(pNode.next!=null && pNode.next.left!=pNode) {
pNode = pNode.next;
}
return pNode.next;
}
}
return null;
}
public TreeLinkNode findMin(TreeLinkNode node) {
while(node.left!=null) {
node = node.left;
}
return node;
}
}
- 思考:如果要找到前序遍历的下一个节点呢?后序遍历的下一个节点呢?
同理:对于前序遍历,分情况为
- 若当前节点存在左子树 ---- > 下一个节点就是这个左子树
- 若当前节点为父亲节点的左孩子且自身不存在左子树:
Ⅰ.若父亲节点存在右子树 -----> 下一个节点就是父亲节点的右子树
Ⅱ.若父亲节点不存在右子树 -----> 向上进行回溯,如果找到一个节点存在右节点,则:下一个节点就是这个节点的右节点
Ⅲ.若父亲节点不存在右子树 ------> 向上回溯,一直回溯到根节点也没找到存在右节点的节点,则当前节点没有下一个节点 - 若当前节点为父亲节点的右孩子且自身不存在左子树:
Ⅰ.向上一直回溯到根节点 -------> 若根节点存在右孩子,则下一个节点为根节点的右孩子
Ⅱ.向上一直回溯到根节点 -------> 若根节点不存在右孩子,则下一个节点不存在
后序遍历同理:
- 若当前节点为其父节点的左孩子且父节点存在右子树 ---- > 下一个节点就是这个右子树中最靠左的元素
- 若当前节点为其父节点的右孩子 ---- >下一个节点就是其父节点
- 第九题
题目:用两个栈实现队列
代码实现
- 剑指Offer
import java.util.Stack;
/*
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
*/
public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void push(int node) {
stack1.add(node);
}
public int pop() {
if(stack2.isEmpty()) {
while(!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
return stack2.pop();
}else {
return stack2.pop();
}
}
}
- 个人思路
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.add(node);
}
public int pop() {
while(!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
int res = stack2.pop();
while(!stack2.isEmpty()) {
stack1.push(stack2.pop());
}
return res;
}
}
- 第十题
题目:斐波那契数列(注意:不能使用递归!------- > 过多的重复无效运算!),利用循环求解:
代码实现
public class Solution {
public int Fibonacci(int n) {
if(n==0 || n==1) {
return n;
}
int fibOne=1;
int fibTwo=0;
int fibN=0;
for(int i=2;i<=n;i++) {
fibN = fibOne + fibTwo;
fibTwo = fibOne;
fibOne = fibN;
}
return fibN;
}
}