极客网个人刷题记录汇总

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

    /**
    * 思路:左下角的值是一行中最小,一列中最大的,所以从这个值开始比较,如果比这个值大,就将列加1,再比较,
    * 如果比这个值小,就将行加1,往上查,总的时间复杂度为O(M+N)
    */
    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 = rows-1;
        int col = 0;
        while(row>=0 && col<cols){
            if(array[row][col]<target){
                col++;
            }else if(array[row][col]>target){
                row--;
            }else{
                return true;
            }
        }
        return false;
    }

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

  public String replaceSpace(StringBuffer str) {
    	if(str!=null){
            return str.toString().replaceAll(" ","%20");
        }
        return null;
    }

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

/**
* 非递归方法,因为链表是从头到尾遍历的,但题目要求从尾到头的输出
* 我们可以利用ArrayList的add重载方法,没次添加数据都添加在第一个位置
*/
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> result = new ArrayList();
        while(listNode!=null){
            result.add(0,listNode.val);
            listNode = listNode.next;
        }
        return result;
    }
}



/**
* 递归方法
* 
*/
public class Solution {
    ArrayList<Integer> result = new ArrayList();
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        if(listNode!=null){
            printListFromTailToHead(listNode.next);
            result.add(listNode.val);
        }
        return result;
    }
}

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

/**
* 思路:栈:先进后出,队列:先进先出,其中一个栈专门用来接收存,另一个栈用来弹出数据,如果数据为空,* 将栈1的数据都压入栈2,这样需要
*/
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();
    }
}

 

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

/**
* 裴波那契数列特点F(1)=1;F(2)=1;F(n)= F(n-1)+F(n-2) (n>=3);
* 时间复杂度:O(2^n)
* 空间复杂度:O(1)
*/
public class Solution {
    public int Fibonacci(int n) {
        if(n<=1){
            return n;
        }
        return Fibonacci(n-1) + Fibonacci(n-2);
    }
}

/**
* 时间复杂度O(n)
* 空间复杂度O(n)
*/
public int Fibonacci(int n) {
        int[] num = new int[40];
        num[0] = 0;
        num[1] = 1;
       
        for(int i=2;i<=n;i++){
            num[i]= num[i-1]+num[i-2];
        }
        return num[n];
    }

/**
* 时间复杂度O(n)
* 空间复杂度O(1)
*/
public int Fibonacci(int n) {
        if(n == 0){
            return 0;
        }else if(n == 1){
            return 1;
        }
        int sum = 0;
        int two = 0;
        int one = 1;
        for(int i=2;i<=n;i++){
            sum = two + one;
            two = one;
            one = sum;
        }
        return sum;
    }

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

首先可知,第一阶有只能一步,一种;,第二阶可以两次一步、一次两步两种

若楼梯阶级 n = 3
跳 2 步到 3:剩下的是第一步没跳,起始跳到第一步只有一种
跳 1 步到 3:剩下的是第二步没跳,起始跳到第二步有两种
通过分类讨论,问题规模就减少了:

若楼梯阶级 n = n
跳 2 步到 n:剩下的是第 n - 2 步没跳,起始跳到第 n - 2 步设它为 pre2 种
跳 1 步到 n:剩下的是第 n - 1 步没跳,起始跳到第 n - 1 步设它为 pre1 种
同时可以发现第 n 阶的解法,只要用到 n - 1 和 n - 2 阶是多少,其他的不用考虑,因此用两个变量临时存下来即可

public class Solution {
    public int JumpFloor(int target) {
        if(target <= 2){
            return target;
        }
        int pre2 = 1, pre1 = 2;
        for (int i = 3; i <= target; i++){
            int cur = pre2 + pre1;
            pre2 = pre1;
            pre1 = cur;
        }
        return pre1;
    }
}

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

/**
* 假设跳到第n个台阶的方法一共有f(n)种,从最后一个台阶开始推,可以从第n-1个台阶跳1个台阶一下到上,
* 也可以从第n-2个台阶跳2个台阶一下跳上,依次类推。。。而跳到第n-1个台阶有f(n-1)中方法,跳到第n-2
* 个台阶有f(n-2)中方法,那么f(n)=f(n-1)+f(n-2)+...f(1); f(n-1) = f(n-2)+f(n-3)+...+f(1)
* 那么就有f(n) = 2*f(n-1);f(n)= 2^2 *f(n-2); f(n) = 2^(n-1) *f(1);而f(1) = 1;
* 最后得出f(n) = 2^(n-1);
*/
public class Solution {
    public int JumpFloorII(int target) {
        return (int)Math.pow(2,target-1);
    }
}

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

/**
* 思路:竖着放相当于一下跳1个台阶,横着放相当于一下跳2个台阶,所以也是斐波那契数列
*/
public class Solution {
    public int RectCover(int target) {
        if(target<=2){
            return target;
        }
        int pre1 = 1;
        int pre2 = 2;
        for(int i=3;i<=target; i++){
            int count  = pre1+pre2;
            pre1 = pre2;
            pre2 = count;
          
        }
        return pre2;
    }
}

9.输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

/**
* 如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就**会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。
*举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两*位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。
*/
public class Solution {
    public int NumberOf1(int n) {
        int count = 0;
        while(n!=0){
            count ++;
            n = n & (n-1);
        }
        return count;
    }
}

10.给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。保证base和exponent不同时为0

public class Solution {
    /**
    * 方法一:直接调用库函数
    */
    public double Power(double base, int exponent) {
        return Math.pow(base, exponent);
    }
    
    /**
    * 方法二:暴力法
    */
    public double Power(double base, int exponent) {
        if(exponent==0){
            return 1;
        }
        if(exponent == 1){
            return base;
        }
        boolean isNegative = exponent<0;
        if(isNegative){
            exponent = Math.abs(exponent);
        }
       double result = base;
        for(int i=1; i<exponent; i++){
            result  = result * base;
        }
        return isNegative?1/result:result;
    }
}

11.输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

//思路一:可以新开辟两个数组,一个存奇数,一个存偶数,然后将两个数组合并
//思路二:用两个变量i、j控制下标,遍历数组中每个元素,如果遇到偶数,则停下来,开始从其后面一位遍历,如果遇到奇数,则将当前j位置的元素需要插入到i位置,但不能直接插入,先用一个临时变量暂存,然后将i到j-1位置的数都后移一位,再将奇数插入到i的位置。
public class Solution {
    
    public void reOrderArray(int [] array) {
        for(int i = 0;i<array.length; i++){
            if(array[i] %2==0){
                for(int j=i+1;j<array.length; j++){
                    if(array[j]%2==0){
                        //如果遍历到最后一位了,还是偶数,说明数组结构已经满足要求,结束全过程
                        if(j==array.length-1){
                            return;
                        }
                    }else{
                        int temp = array[j];
                        while(i<j){
                            array[j] = array[j-1];
                            j--;
                        }
                        array[i] = temp;
                        break;
                    }
                }
            }
        }
    }
}

12.输入一个链表,输出该链表中倒数第k个结点。

//思路一:倒数第k个,就是正着数的第n-k+1个,n为链表总个数。所以先计算出链表总个数,然后从第一个元素开始遍历,小于n-k+1就将后一位赋值给当前节点,不满足循环条件时,即为找到了倒数第k个节点
public class Solution {
    public ListNode FindKthToTail(ListNode head ,int k) {
        int totalCount = 0;
        if(head!=null){
            totalCount++;
        }else{
            return null;
        }
        ListNode tempNode = head.next;
        while(tempNode!=null){
            totalCount++;
            tempNode = tempNode.next;
        }
        if(k>totalCount){
            return null;
        }
        ListNode result = head;
        int i = 1;
        while(i<totalCount-k+1){
            result = result.next;
            i++;
        }
        return result;
        
    }

    //思路二:很多链表问题活用指针都能解决问题,如果一个解决不了,那就用两个。本题的解决思路,倒数第k个元素,就是正着数第n-k+1个(从1开始),如果快指针先走k-1步,然后慢指针和快指针再一起走,这样两者相差k-1步,当快指针走到n时,那么慢指针走到n-(k-1),也即n-k+1,就是我们要找的倒数第k个元素。
    public ListNode FindKthToTail(ListNode head , int k) {
        if(k<1){
            return null;
        }
        ListNode fast = head;
        ListNode low = head;
        for(int i=1;i<k ; i++){
            if(fast == null){
                return null;
            }
            fast = fast.next;
        }
        if(fast==null){
            return null;
        }
        while(fast.next!=null){
            fast = fast.next;
            low = low.next;
        }
        return low;
    }
}

13.输入一个链表,反转链表后,输出新链表的表头

public class Node{

    public int value;
    public Node next;

    public Node(int data){
        this.value = data;
    }
}

/**
*1.遍历法
*目的:需要从第一个节点开始,遍历修改每个节点的next属性
*思路:遍历每一个节点,用临时变量next存储当前节点的下一个节点,以保证遍历能够持续,修*改当前节点的next属性,也即使其指向prev节点,
*用临时变量prev存储修改后的节点,
public static Node reverseList(Node node){
 
    Node prev = null;
    Node next = null;
    while(node != null){
        //先将当前节点的next赋值给临时变量,为了能保证循环继续,因为第二步要修改其next
        next = node.next;  
        //将上一步遍历后的节点设置给当前节点的next,实际上完成了一次翻转。
        node.next = prev;
        //然后将修改后的当前节点在赋值给prev,作为处理结果供下次遍历使用。
        prev = node;
        //将next节点赋值给当前节点,判断循环是否继续
        node = next; 
    }
    
    return prev;
    
}


/**
* 2.递归法:递归法是从最后一个Node开始,弹栈的过程中将指针顺序置换的。
* 递归实质上就是系统帮你压栈的过程,系统在压栈的时候会保留现场。
*/
public static Node reverse(Node node){

    if(node == null || node.next == null){
        return node;
    }
    
    Node temp = node.next;
    
    Node newNode = reverse(node.next);
    
    temp.next = node;
    node.next = null;
    
    return newNode;
}

我看看一个递归过程1->2->3->4,
1)程序到达 Node newNode = reverse(node.next);时进入递归。
2)假设此时递归到达了3节点,此时node = 3,temp = 4;
3)执行reverse(node.next),传入node为4的节点,返回node为4的节点。
4)接下来就是弹栈过程,执行temp.next = node;相当于4->3.
5) 执行node.next = null,即把3节点指向4节点的指针断掉。
6)返回新链表的头结点newNode,继续恢复2节点的压栈现场。最后完成整个链表的翻转。

14.打印10000以内的猫扑素数

形如以 2 开头, 之后跟任意多个 3 的十进制整数而且是个素数, 则它是猫扑素数. 如 2, 23, 233, 2333, 23333 都是猫扑素数, 而 233333 则不是, 它可以分解为 353 x 661.

//判断是否是猫扑数
public static boolean isMopNum(int n){
    if(n<10) 
        return n==2;
    else
        return n%10 == 3 && isMopNum(n/10);
}

public static boolean isPrimeNum(int n){
    if(n<2) return false;
    for(int i = 2; i<= Math.squrt(n); i++){
        if(n%i ==0){
           return false; 
        }
    }
    return true;
}

public static void main(String[] args){
    for(int i = 0;i<10000;i++){
         if(isMopNum(i) && isPrimeNum(n)){
            System.Out.println(i);
        }
    }
}

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值