11天刷完《剑指Offer》/ Day1:第1~10题

2月底前基本熟悉算法,把剑指offer刷完!

part1 :

T1. 二维数组中的查找
T2. 替换空格
T3. 从尾到头打印链表
T4. 重建二叉树
T5. 用两个栈实现队列
T6. 旋转数组的最小数字
T7. 斐波那契数列
T8. 跳台阶
T9. 变态跳台阶
T10. 矩阵覆盖

part2 :

T1. 二维数组中的查找

  • 题目

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

  • 解题思路:

1.暴力法:
挨个遍历数组,找出该数。

public class Solution {
     public boolean Find(int target, int [][] array) {
        for(int i=0;i

2.从右上找:
对于右上角的数m,是此行最大,此列最小,
用m和target 判断,每次删除一行或一列。

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

T2. 替换空格

  • 题目描述

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

  • 解题思路

1.调用自带函数

public class Solution {
    public String replaceSpace(StringBuffer str) {
    return str.toString().replace(" ","%20");
    }
  }

2.挨个比对,建新字符串

public class Solution {
    public String replaceSpace(StringBuffer str) {
    	StringBuilder cm=new StringBuilder();
        for(int i=0;i<str.length();i++){
            if(str.charAt(i)==' '){
                cm.append("%20");
            }else{cm.append(str.charAt(i));}
        }
        return cm.toString();
    }
}

String、StringBuffer和StringBuilder的区别
一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString()方法将其转换为一个String对象。

charAt() 方法用于返回指定索引处的字符。索引范围为从 0 到 length() - 1。

语法 public char charAt(int index)

T3. 从尾到头打印链表

  • 题目描述

输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

  • 解题思路

1.listNode 是链表,只能从头遍历到尾,但是输出却要求从尾到头,这是典型的"先进后出",我们可以想到栈!
ArrayList 中有个方法是 add(index,value),可以指定 index 位置插入 value 值
所以我们在遍历 listNode 的同时将每个遇到的值插入到 list 的 0 位置,最后输出 listNode 即可得到逆序链表

import java.util.*;
public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> list = new ArrayList<>();
        ListNode tmp = listNode;
        while(tmp!=null){
            list.add(0,tmp.val);
            tmp = tmp.next;
        }
        return list;
    }
}

2.递归

import java.util.*;
public class Solution {
    ArrayList<Integer> list = new ArrayList();
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        if(listNode!=null){
            printListFromTailToHead(listNode.next);
            list.add(listNode.val);
        }
        return list;
    }
}

T4. 重建二叉树!

  • 题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回

  • 解题思想

递归思想,每次将左右两颗子树当成新的子树进行处理,中序的左右子树索引很好找,前序的开始结束索引通过计算中序中左右子树的大小来计算,然后递归求解,直到startPre>endPre||startIn>endIn说明子树整理完到。方法每次返回左子树活右子树的根节点


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;
    }
    //前序遍历{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]){
                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);
                      break;
            }
                 
        return root;
    }
}

T5. 用两个栈实现队列

  • 题目描述

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

  • 解题思路

栈A用来作入队列,栈B用来出队列,当栈B为空时,栈A全部出栈到栈B,栈B再出栈(即出队列)

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.size()<=0){
>          while(stack1.size()!=0)
>          {stack2.push(stack1.pop());}     }
>     return stack2.pop();
也可以是/等于:
>  if (stack2.empty()) {
>             while (!stack1.empty()) {
>                 stack2.push(stack1.pop());
>             }
>         }
>         return stack2.pop();

 
    }
}

T6. 旋转数组的最小数字

  • 题目描述

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

  • 解题思路

二分法 o(lgn)

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        if (array.length == 0)
            return 0;
                int left = 0;
                int right = array.length - 1;
                int middle = -1;
                while (array[left]>=array[right]) {
                    if(right-left==1){
                        middle = right;
                        break;
                    }
                   
                    middle = left + (right - left) / 2;
                    //判断middle是否在左边递增序列
                    if (array[middle] >= array[left]) {
                        left = middle;
                    }
                    //判断middle是否在右边递增序列
                    if (array[middle] <= array[right]) {
                        right = middle;
                    }
                }
                return array[middle];
            }
}

二分法查找:是一种在有序数组中查找某一特定元素的搜索算法。
练习实现!!

暴力对比一般情况也可以,但是遇到数据量很大时,时间复杂度很大,o(n)。

T7. 斐波那契数列

  • 题目描述

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。 n<=39

  • 解题思路
public class Solution {
    public int Fibonacci(int n) {
        int a = 0;
        int b = 1;
        //n减去1是否大于0
        while(n-->0){
            b = a + b;
            a = b - a;
        }
        return a;
    }
}

T8. 跳台阶

  • 题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

  • 解题思路
public class Solution {
    public int JumpFloor(int target) {
        //分类讨论
        if(target <= 2){
            return target;
        }
        //斐波那契数列,只考虑n-1和n-2的跳法
        int pre1 = 2,pre2 = 1;
        for (int i = 3; i <= target; i++){
            int cur = pre2 + pre1;
            pre2 = pre1;
            pre1 = cur;
        }
        return pre1;
    }
}

T9. 变态跳台阶

  • 题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

  • 解题思路
public class Solution {
    public int JumpFloorII(int target) {
        int sum=1;//当n=1,跳法为1
        if(target==0)
            return 0;
//易知 f(n)=f(n-1)+f(n-2)+……f(1)
//f(n-1)=f(n-2)+……f(1)
//两式相减得f(n)=2f(n-1)
        for(int i=1;i<target;i++)
            sum=2*sum;
        return sum;
    }
}

T10. 矩阵覆盖

  • 题目描述

我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

比如n=3时,2*3的矩形块有3种覆盖方法

  • 解题思路
    11天刷完《剑指Offer》/ Day1:第1~10题_第1张图片
    n=1到n=4的情况:
    11天刷完《剑指Offer》/ Day1:第1~10题_第2张图片
    *与T8一样
public class Solution {
    public int RectCover(int target) {
        if (target <= 2){
            return target;
        }
        int pre1 = 2; // n 最后使用一块,剩下 n-1 块的写法
        int pre2 = 1; // n 最后使用两块,剩下 n-2 块的写法
        for (int i = 3; i <= target; i++){
            int cur = pre1 + pre2;
            pre2 = pre1;
            pre1 = cur;
        }
        return pre1; //相对于 n+1 块来说,第 n 种的方法
    }
}

你可能感兴趣的:(11天刷完《剑指Offer》/ Day1:第1~10题)