本人在做剑指offer试题的过程中所用的方法以及参考别人好的算法,进行了一个总结
1.在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
public class Solution {
public boolean Find(int target, int [][] array) {
int len = array[0].length;
int len1 = array.length;
for(int i=0;i<len;i++){
for(int j=0;j<len1;j++){
if (target==array[i][j]){
return true;
}
}
}
return false;
}
}
2.请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
public class Solution {
public String replaceSpace(StringBuffer str) {
if(str==null){
return null;
}
StringBuilder newStr = new StringBuilder();
for(int i=0;i<str.length();i++){
if(str.charAt(i)==' '){
newStr.append('%');
newStr.append(2);
newStr.append(0);
}else{
newStr.append(str.charAt(i));
}
}
return newStr.toString();
}
}
//在不开辟新的空间的基础上
public class Solution {
public String replaceSpace(StringBuffer str) {
int spacenum = 0;//spacenum为计算空格数
for(int i=0;i<str.length();i++){
if(str.charAt(i)==' ')
spacenum++;
}
int indexold = str.length()-1; //indexold为为替换前的str下标
int newlength = str.length() + spacenum*2;//计算空格转换成%20之后的str长 度
int indexnew = newlength-1;//indexold为为把空格替换为%20后的str下标
str.setLength(newlength);//使str的长度扩大到转换成%20之后的长度,防止下标越界
for(;indexold>=0 && indexold<newlength;--indexold){
if(str.charAt(indexold) == ' '){ //
str.setCharAt(indexnew--, '0');
str.setCharAt(indexnew--, '2');
str.setCharAt(indexnew--, '%');
}else{
str.setCharAt(indexnew--, str.charAt(indexold));
}
}
return str.toString();
}
}
3.输入一个链表,从尾到头打印链表每个节点的值。
/**
* public class ListNode {
* int val;
* ListNode next = null;
*
* ListNode(int val) {
* this.val = val;
* }
* }
*
*/
import java.util.Stack;
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
Stack<Integer> s = new Stack<Integer>();
while(listNode != null){
s.push(listNode.val);
listNode=listNode.next;
}
ArrayList<Integer> list=new ArrayList<>();
while(!s.isEmpty()){
list.add(s.pop());
}
return list;
}
}
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; }
* }
*/
import java.util.*;
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if(in.length==0||pre.length==0){
return null;
}
TreeNode treeNode=new TreeNode(pre[0]);
for(int i=0;i<in.length;i++){
if(pre[0]==in[i]){
treeNode.left=reConstructBinaryTree(Arrays.copyOfRange(pre,1,i+1),Arrays.copyOfRange(in,0,i));
treeNode.right=reConstructBinaryTree(Arrays.copyOfRange(pre,i+1,pre.length),Arrays.copyOfRange(in,i+1,in.length));
}
}
return treeNode;
}
}
5.用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
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(stack1.isEmpty()&&stack2.isEmpty()){
throw new RuntimeException("Queue is empty");
}
if(stack2.isEmpty()){
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
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
int low = 0 ;
int high = array.length - 1;
while(low < high){
int mid = low + (high - low) / 2;
if(array[mid] > array[high]){
low = mid + 1;
}else if(array[mid] == array[high]){
high = high - 1;
}else{
high = mid;
}
}
return array[low];
}
}
7.大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。
n<=39
public class Solution {
public int Fibonacci(int n) {
int fb1=1;
int fb2=1;
int fb3=0;
if(n==0){
return 0;
}
else if(n==1||n==2){
return 1;
}else{
for(int i=3;i<=n;i++){
fb3=fb1+fb2;
fb1=fb2;
fb2=fb3;
}
return fb3;
}
}
}
8.一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。代码如下所示:
public class Solution {
public int JumpFloor(int target) {
if(target<=0){
return -1;
}else if(target==1){
return 1;
}else if(target==2){
return 2;
}else{
return JumpFloor(target-1)+JumpFloor(target-2);
}
}
}
9.一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。代码如下所示:
public class Solution {
public int JumpFloorII(int target) {
if(target<=0){
return -1;
}else if(target==1){
return 1;
}else{
return 2*JumpFloorII(target-1);
}
}
}
10.我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?代码实现如下:
public class Solution {
public int RectCover(int target) {
if(target<=0){
return 0;
}
if(target*2==2){
return 1;
}else if(target*2==4){
return 2;
}else{
return RectCover(target-1)+RectCover(target-2);
}
}
}
11.输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。代码实现如下所示:
public class Solution {
public int NumberOf1(int n) {
int count=0;
int flag=1;
while(flag!=0){
if((n&flag)!=0){
count++;
}
flag=flag<<1;
}
return count;
}
}
//最优解
public class Solution {
public int NumberOf1(int n) {
int count=0;
while(n!=0){
++count;
n=(n-1)&n;
}
return count;
}
}
12.给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。代码实现如下所示:
public class Solution {
public double Power(double base, int exponent) {
double res=1,cuur=base;
int n;
if(exponent>0){
n=exponent;
}else if(exponent<0){
if(base==0){
new Throwable("分母不能为0");
}
n=-exponent;
}else{
return 1;
}
while(n!=0){
if((n&1)==1){
res*=cuur;
}
cuur*=cuur;
n=n>>1;
}
return exponent>0?res:1/res;
}
}
13.输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。代码实现如下所示:
public class Solution {
public void reOrderArray(int [] array) {
int k=0;
int temp;
for(int i=0;i<array.length;i++){
if(array[i]%2==0){
k=i;
break;
}
}
int m=k;
for(int j=m+1;j<array.length;j++){
if(array[j]%2!=0){
temp=array[j];
for(int n=j-1;n>=k;n--){
array[n+1]=array[n];
}
array[k]=temp;
k++;
}
}
}
}
14.输入一个链表,输出该链表中倒数第k个结点。代码实现如下所示:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
ListNode pre=head;
ListNode last=head;
if(head==null||k<=0){
return null;
}
for(int i=1;i<k;i++){
if(last.next!=null){
last=last.next;
}else{
return null;
}
}
while(last.next!=null){
last=last.next;
pre=pre.next;
}
return pre;
}
}
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 pre=head.next;
ListNode temp=head.next;
head.next=null;
while(pre!=null){
temp=pre.next;
pre.next=head;
head=pre;
pre=temp;
}
return head;
}
}
16.输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。代码实现如下所示:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
if (list1==null){
return list2;
}
if (list2==null){
return list1;
}
if (list1==null&&list2==null){
return null;
}
ListNode head;
if (list1.val>list2.val){
head=list2;
list2=list2.next;
head.next=null;
}else{
head=list1;
list1=list1.next;
head.next=null;
}
ListNode pre=head;
ListNode temp;
while(list1!=null && list2!=null){
if (list1.val>list2.val){
temp=list2.next;
pre.next=list2;
pre=pre.next;
pre.next=null;
list2=temp;
}else{
temp=list1.next;
pre.next=list1;
pre=pre.next;
pre.next=null;
list1=temp;
}
}
while(list1!=null){
pre.next=list1;
break;
}
while(list2!=null){
pre.next=list2;
break;
}
return head;
}
}
17.输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构),代码实现如下所示:
public class Solution {
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
boolean result = false;
if(root1 != null && root2 != null){
if(root1.val == root2.val){
result = DoesTree1HaveTree2(root1,root2);
}
if(!result){result = HasSubtree(root1.left, root2);}
if(!result){result = HasSubtree(root1.right, root2);}
}
return result;
}
public boolean DoesTree1HaveTree2(TreeNode root1,TreeNode root2){
if(root1 == null && root2 != null) return false;
if(root2 == null) return true;
if(root1.val != root2.val) return false;
return DoesTree1HaveTree2(root1.left, root2.left) && DoesTree1HaveTree2(root1.right, root2.right);
}
}
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){
return;
}
TreeNode temp=root.left;
root.left=root.right;
root.right=temp;
Mirror(root.left);
Mirror(root.right);
}
}
19.输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 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.具体代码实现如下所示:
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> list=new ArrayList();
int row=matrix.length;
int column=matrix[0].length;
int circle=((row<column?row:column)-1)/2+1;
for(int i=0;i<circle;i++){
for(int j=i;j<column-i;j++){
list.add(matrix[i][j]);
}
for(int k=i+1;k<row-i;k++){
list.add(matrix[k][column-i-1]);
}
for(int m=column-i-2;(m>=i&&row-i-1!=i);m--){
list.add(matrix[row-i-1][m]);
}
for(int n=row-i-2;(n>i&&column-i-1!=i);n--){
list.add(matrix[n][i]);
}
}
return list;
}
}
20.定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。具体代码实现如下所示:
import java.util.Stack;
import java.util.Arrays;
public class Solution {
private int size;
private int min=Integer.MAX_VALUE;
private Stack<Integer> minStack=new Stack<>();
private Integer[] elements=new Integer[10];
public void push(int node) {
ensureCapacity(size+1);
elements[size++]=node;
if(node<=min){
minStack.push(node);
min=minStack.peek();
}else{
minStack.push(min);
}
}
private void ensureCapacity(int size) {
int len=elements.length;
if(size>len){
int newLen=(len*3)/2+1;
elements=Arrays.copyOf(elements,newLen);
}
}
public void pop() {
Integer top=top();
if(top!=null){
elements[size-1]=(Integer)null;
}
size--;
minStack.pop();
min=minStack.peek();
}
public int top() {
if(!empty()){
if(size-1>=0){
return elements[size-1];
}
}
return (Integer)null;
}
private boolean empty() {
return size==0;
}
public int min() {
return min;
}
}