剑指Offer 刷题笔记(10/66)——JAVA

如果你碰巧点进来想看解题思路的话,可以看下这位dalao写的.挺详细的~
https://blog.csdn.net/flushhip/article/details/79392028#commentBox

文章目录

      • 1.二维数组中的查找
      • 2.替换空格
      • 3.从尾到头打印链表
      • 4.重建二叉树
      • 5.用两个栈来实现一个队列
      • 6.旋转数组的最小数字
      • 7.斐波那契数列
      • 8.跳台阶
      • 9.变态跳台阶
      • 10.矩形覆盖


1.二维数组中的查找

题目:在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。(链接)
解析:矩阵是有序的,从左下角来看,向上数字递减,向右数字递增。
因此从左下角开始查找,当Target比左下角数字大时——右移;Target比左下角数字小时——上移。

public class Solution {
    public boolean Find(int target, int [][] array) {
        int row = array.length-1;
        int col = 0;
        while( row>=0 && col<array[0].length ){
            if(target==array[row][col])
                return true;
            else if(target > array[row][col])
                col++;
            else
                row--;
        }
        return false;
    }
}

2.替换空格

题目:请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。(链接)
解析:从左到右遍历“ ”数量,扩大字符串容量(防止下标越界),从右到左替换。
剑指Offer 刷题笔记(10/66)——JAVA_第1张图片

public class Solution {
    public String replaceSpace(StringBuffer str) {
    	int count = 0;    //空格总数
        int i = 0;
        for(; i < str.length(); i++){
            if(str.charAt(i)==' ')
                count++;
        }
        i--;
        str.setLength( str.length() + count * 2 );
        for(int j = str.length()-1; count>0; i--){
            if(str.charAt(i)!=' ')
                str.setCharAt(j--, str.charAt(i));
                //str.charAt(j)=str.charAt(i);
            else{
                str.setCharAt(j--, '0');
                str.setCharAt(j--, '2');
                str.setCharAt(j--, '%');
                count--;
            }
        }
        return str.toString();
    }
}

3.从尾到头打印链表

题目:输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。(链接)
解析:(先进后出) 两种方法: ①递归 ②堆栈(java.util.Stack)

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*/
import java.util.ArrayList;
public class Solution {
    ArrayList<Integer> arr = new ArrayList<Integer>();
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        if(listNode!=null){
            printListFromTailToHead(listNode.next);
            arr.add(listNode.val);
        }
        return arr;
    }
}
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        Stack <Integer> stack = new Stack <Integer>(); 
        while(listNode!= null){
            stack.push(listNode.val); 
            listNode = listNode.next;     
        }
        
        ArrayList <Integer> list = new ArrayList <Integer>();
        while(!stack.isEmpty()){
            list.add(stack.pop()); 
        } 
        return list; 
    }
}

4.重建二叉树

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。(链接)
解析:利用前序遍历第一个数字为根,用这个根在中序遍历中查找,左边的就是左子树,右边的就是右子树,算出左右子树的长度,用其长度在前序遍历中划分出左右子树,重复上述过程,就可以重建这颗二叉树了。
剑指Offer 刷题笔记(10/66)——JAVA_第2张图片

/**
 * 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) {
	    TreeNode root = reConstructBinaryTree(pre,0,pre.length-1,in,0,in.length-1);
	    return root;
	}
	       
    public 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]) {
    			root.left = reConstructBinaryTree(pre,++startPre,startPre+(i-startIn),in,startIn,i-1);
    			root.right = reConstructBinaryTree(pre,startPre+(i-startIn),endPre,in,i+1,endIn);
    			break;
    		}
    	}
    	return root;
    }
}

5.用两个栈来实现一个队列

题目:用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。(链接)
解析:判断进时,栈2是否为空,不为空,则栈2元素倒回到栈1;出时,将栈1元素全部弹到栈2中,直到栈1为空。
1,元素先依次进入栈1,再从栈1依次弹出到栈2,然后弹出栈2顶部的元素,整个过程就是一个队列的先进先出
2,但是在交换元素的时候需要判断两个栈的元素情况:
①“进队列时”,队列中是否还有元素,若有,说明栈2中的元素不为空,此时就先将栈2的元素倒回到栈1 中,保持在“进队列状态”。
②“出队列时”,将栈1的元素全部弹到栈2中,保持在“出队列状态”。

import java.util.Stack;

public class Solution {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
    
    public void push(int node) {
        while(!stack2.empty()){
            stack1.push(stack2.pop());
        }
        stack1.push(node);
    }
    
    public int pop() {
        while(!stack1.empty()){
            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) {
        if(array.length==0)
            return 0;
        int l=0, r=array.length-1;
        while( l<r && array[l]>=array[r] ){
            int mid = (l+r)/2;
            if(array[l]==array[r] && array[l]==array[mid]){
                int min = array[l];
                return min;
            }
            if(array[mid]>=array[l])
                l=mid+1;
            else
                r=mid;
        }
        return array[l];
    }
}

7.斐波那契数列

题目:大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。n<=39(链接)
解析:斐波拉契数列的定义:

  • F0=0,F1=1;
  • Fn=Fn-1+Fn-2 (n ≥ 2)

(int型整数只能保存F0→F46

public class Solution {
    public int Fibonacci(int n) {
        if(n==0)
            return 0;
        if(n==1)
            return 1;
        int f0=0,f1=1,ret=0;
        for(int i=2; i<=n; i++){
            ret=f0+f1;
            f0=f1;
            f1=ret;
        }
        return ret;
    }
}

8.跳台阶

题目:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。(链接)
解析:最简单的动态规划,考虑最后跳上第n阶台阶,有两种方式往上跳:
从第n - 1阶往上跳一级到第n阶;
从第n - 2阶往上跳二级到第n阶。
那么f(i)表示该青蛙跳上一个i级的台阶总共跳法。故f(i)=f(i−1)+f(i−2),f(0)=f(1)=1
这就是变形版的斐波拉契数列啊,直接求解。
【比较倾向于找规律的解法,f(1) = 1, f(2) = 2, f(3) = 3, f(4) = 5, 可以总结出f(n) = f(n-1) + f(n-2)的规律,但是为什么会出现这样的规律呢?假设现在6个台阶,我们可以从第5跳一步到6,这样的话有多少种方案跳到5就有多少种方案跳到6,另外我们也可以从4跳两步跳到6,跳到4有多少种方案的话,就有多少种方案跳到6,其他的不能从3跳到6什么的啦,所以最后就是f(6) = f(5) + f(4);】

public class Solution {
    public int JumpFloor(int target) {
        if(target == 1)
            return 1;
        if(target == 2)
            return 2;
        int f1=1,f2=2,ret=0;
        for(int i=3;i<=target;i++){
            ret=f1+f2;
            f1=f2;
            f2=ret;
        }
        return ret;
    }
}

9.变态跳台阶

题目:一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。(链接)
解析:f(n) = f(n-1) + f(n-2) + f(n-3) + … + f(n-(n-1)) + f(n-n) => f(0) + f(1) + f(2) + f(3) + … + f(n-1)
继续简化:
f(n-1) = f(0) + f(1)+f(2)+f(3) + … + f((n-1)-1) = f(0) + f(1) + f(2) + f(3) + … + f(n-2)
f(n) = f(0) + f(1) + f(2) + f(3) + … + f(n-2) + f(n-1) = f(n-1) + f(n-1)
可以得出:
f(n) = 2*f(n-1)
① 得出最终结论,在n阶台阶,一次有1、2、…n阶的跳的方式时,总得跳法为:

f(n) =     | 1       ,(n=1 )

           | 2*f(n-1),(n>=2)

② 这是一个首项为1,公比为2的等比数列啊,可得到最终表达式:f(n)=2n−1

public class Solution {
    public int JumpFloorII(int target) {
        if(target == 1)
            return 1;
        int f=1,fn=0;
        for(int i=2;i<=target;i++){
            fn=2*f;
            f=fn;
        }
        return fn;
    }
}
public class Solution {
    public int JumpFloorII(int target) {

        return 1<<(target-1);
    }
}

10.矩形覆盖

题目:我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?(链接)
解析:依旧是斐波那契数列:f(n)=f(n−1)+f(n−2),f(1)=1,f(2)=2
剑指Offer 刷题笔记(10/66)——JAVA_第3张图片

public class Solution {
    public int RectCover(int target) {
        if(target==1)
            return 1;
        if(target==2)
            return 2;
        int f1=1,f2=2,fn=0;
        for(int i=3;i<=target;i++){
            fn=f1+f2;
            f1=f2;
            f2=fn;
        }
        return fn;
    }
}

你可能感兴趣的:(【算法与数据结构】,---剑指offer刷题)