【剑指offer@JZ31--JZ40】

JZ31:从1到n,1出现的次数

题目描述:1~13中包含1的数字有1、10、11、12、13因此共出现6次,(从1 到 n 中1出现的次数?)。
解题思路:把这个数转化成字符数组,逐个去遍历统计

public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        int count=0;
        while(n>0){
            String str=String.valueOf(n);//转换成字符串
            char[] arr=str.toCharArray();
            for(int i=0;i<arr.length;i++){
                if(arr[i]=='1'){
                    count++;
                }
            }
            n--;
        }
        return count;
    }
}

JZ32:把数组排成最小的数

题目描述:输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
解题思路:比较两个字符串s1, s2大小的时候,先将它们拼接起来,比较s1+s2,和s2+s1那个大,如果s1+s2大,那说明s2应该放前面,所以按这个规则,s2就应该排在s1前面。比如3和32拼接成332,32和3拼接成323,332大于323,所以3就和32交换位置,以此推论。

public class Solution{
    public String PrintMinNumber(int[] numbers){
        if(numbers==null||numbers.length==0){
            return "";
        }
        for(int i=0;i<numbers.length;i++){
            for(int j=i+1;j<numbers.length;j++){
                int sum1=Integer.valueOf(numbers[i]+""+numbers[j]);
                int sum2=Integer.valueOf(numbers[j]+""+numbers[i]);
                if(sum1>sum2){
                    int temp=numbers[j];
                    numbers[j]=numbers[i];
                    numbers[i]=temp;
                }
            }
        }
        String str=new String("");
        for(int i=0;i<numbers.length;i++){
            str=str+numbers[i];
        }
        return str;
    }
}

JZ33:丑数

题目描述:把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
解题思路:首先从丑数的定义我们知道,一个丑数的因子只有2,3,5,那么丑数p = 2 ^ x * 3 ^ y * 5 ^ z,换句话说一个丑数一定由另一个丑数乘以2或者乘以3或者乘以5得到,我们只用比较3个数:用于乘2的最小的数、用于乘3的最小的数,用于乘5的最小的,

import java.util.ArrayList;
public class Solution {
    public int GetUglyNumber_Solution(int index) {
        if(index<=0){
            return 0;
        }
        ArrayList<Integer> list=new ArrayList<>();
        list.add(1);
        int i2=0,i3=0,i5=0;
        while(list.size()<index){
            int m2=list.get(i2)*2;
            int m3=list.get(i3)*3;
            int m5=list.get(i5)*5;
            int min=Math.min(m2,Math.min(m3,m5));
            list.add(min);
            if(min==m2)i2++;
            if(min==m3)i3++;
            if(min==m5)i5++;
        }
        return list.get(list.size()-1);
    }
}

JZ34:第一个只出现一次的字符

题目描述:在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)
解题思路:借助java的indexof和lastIndexof方法,两个相等直接返回

public class Solution {
    public int FirstNotRepeatingChar(String str) {
        for (int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            //indexof:返回第一次出现的指定字符串在此字符串中的索引
            //同理,返回最后一次出现的索引
            if (str.indexOf(ch) == str.lastIndexOf(ch))
                return i;
        }
        return -1;
    }
}

JZ35:数组中的逆序对

题目描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
解题思路:这种情况下用归并排序是最合适的,归并排序的思想是先分在和。在分完的时候是统计逆序数对的最好时机。

public class Solution {
    //统计逆序对的个数
    int cnt;
    public int InversePairs(int [] array) {
        if(array.length != 0){
            divide(array,0,array.length-1);
        }
        return cnt;
    }
    //归并排序的分治---分
    public void divide(int[] arr,int start,int end){
        if(start >= end)//递归出口
            return;
        int mid = start + (end - start)/2;
        //递归分
        divide(arr,start,mid);
        divide(arr,mid+1,end);
        merge(arr,start,mid,end);//治
    } 
    public void merge(int[] arr,int start,int mid,int end){
        int[] temp = new int[end-start+1];
        int i=start,j=mid+1,k=0;
        //下面就开始两两进行比较,若前面的数大于后面的数,就构成逆序对
        while(i<=mid && j<=end){
            //若前面小于后面,直接存进去,并且移动前面数所在的数组的指针即可
            if(arr[i] <= arr[j]){
                temp[k++] = arr[i++];
            }else{
                temp[k++] = arr[j++];
                //a[i]>a[j]了,那么这一次,从a[i]开始到a[mid]必定都是大于这个a[j]的,因为此时分治的两边已经是各自有序了
                cnt = (cnt+mid-i+1)%1000000007;
            }
        }
        //各自还有剩余的没比完,直接赋值即可
        while(i<=mid)
            temp[k++] = arr[i++];
        while(j<=end)
            temp[k++] = arr[j++];
        //覆盖原数组
        for (k = 0; k < temp.length; k++)
            arr[start + k] = temp[k];
    }
}

JZ36:两个链表的第一个公共节点

题目描述:输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
解题思路:让p1 p2都往后遍历,想等了说明找到了,返回,不相等但其中一个为空了就返回另一个

public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        ListNode p1=pHead1;
        ListNode p2=pHead2;
        while(p1!=p2){//两个不相等就往后遍历
            p1 = (p1==null ? pHead2 : p1.next);//这个为空了就返回另一个
            p2 = (p2==null ? pHead1 : p2.next);
        }
        return p1;
    }
}

JZ37:数字在排序数组中出现的次数

解题思路:二分查找的前提就是有序,所以这道题就用二分查找来做,找到k值出现的左和右,然后统计

public class Solution {
    public int GetNumberOfK(int [] array , int k) {
       if(array==null||array.length==0){
           return 0;
       }
        int left=0,right=array.length-1,mid=0;
        while(left<right){//二分查找的过程
            mid =left+(right-left)/2;
            if(array[mid]>k){
                right=mid-1;
            }
            else if(array[mid]<k){
                left=mid+1;
            }
            else{
                break;
            }
        }
        int count=0;
        for(int i=left;i<=right;i++){//找到k值出现的左和右,然后统计
            if(array[i]==k)
            count++;
        }
        return count;
    }
}

JZ38:求二叉树的深度

解题思路:树的题目一般都用递归,把左边统计一下,再把右边统计一下,返回大的那个就是它的深度

public class Solution {
    public int TreeDepth(TreeNode root) {
        if(root==null){
            return 0;
        }
        int left=TreeDepth(root.left);
        int right=TreeDepth(root.right);
        return Math.max(left,right)+1;
    }
}

JZ39:平衡二叉树

题目描述:给一棵树,判断是不是平衡二叉树
解题思路:首先知道平衡二叉树任意节点的子树的高度差都小于等于1,判断树是否为空,空则返回true,判断左右子树深度差超过1,返回false.若通过2的判断,对左右子树也判断是否都是平衡二叉树,判断函数为函数自身,递归调用

public class Solution {
    public int TreeDepth(TreeNode root) {
        if(root==null){
            return 0;
        }
        if(root.left==null && root.right==null){
            return 1;
        }
        return 1+Math.max(TreeDepth(root.left),TreeDepth(root.right));
    }
    public boolean IsBalanced_Solution(TreeNode root) {
        if(root==null) return true;
        if(Math.abs(TreeDepth(root.left)-TreeDepth(root.right))>1)
            return false;
        return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
    }
}

JZ40:数组中只出现一次的数字

题目描述:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
解题思路:异或运算规则,相同为0不同为1,当只有一个数出现一次时,我们把数组中所有的数,依次异或运算,成对的就会被异或掉,最后剩下的就是要的单数。还有一种简单方法就是用HashMap的性质,
方法一:运用异或性质

public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        int num=0;
        for(int i=0;i<array.length;i++){
            num^=array[i];//所有数异或,结果为不同的两个数字的异或
        }
        int count=0;//标志位,记录num中的第一个1出现的位置
        for(;count<array.length;count++){
            if((num&(1<<count))!=0){
                break;
            }
        }
        num1[0]=0;
        num2[0]=0;
        for(int i=0;i<array.length;i++){
            if((array[i]&(1<<count))==0){//标志位为0的为一组,异或后必得到一个数字(这里注意==的优先级高于&,需在前面加())
                num1[0]^=array[i];
            }else{
                num2[0]^=array[i];//标志位为1的为一组
            }
        }   
    }
}

方法二:运用HashaMap

import java.util.HashMap;
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        HashMap<Integer,Integer> map=new HashMap<>();
        for(int i=0;i<array.length;i++){
            if(map.containsKey(array[i])){
                map.put(array[i],2);
            }else{
                map.put(array[i],1);//把单独的这个数就统计出来了
            }
        }
        int count=0;
        for(int i=0;i<array.length;i++){
            if(map.get(array[i])==1){
                if(count==0){
                    num1[0]=array[i];
                    count++;
                }
                else{
                    num2[0]=array[i];
                }
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/chris__x/article/details/106911814
今日推荐