剑指Offer系列之题46~题50

46.扑克牌顺子

从扑克牌随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王可以看成任意数字。

找出最大最小值,0的数量,判断最大最小值的差中的空缺数是否小于等于0的个数


1.快排:

快排超时,使用Arrays.sort(numbers);

public class Solution {
    public boolean isContinuous(int [] numbers) {
        //大、小王=任意数字 A=1 J=11 Q=12 K=13  可以认为大小王是0
        //5张牌 可能是无序的
        if(numbers.length<1)
            return false;
        int diff=0;//数字之间的空缺
        int count=0;//大小王的数量
        quickSort(numbers,0,numbers.length-1);
        for(int i=0;i<numbers.length-1;++i){
            if(numbers[i]==0){//大小王的数量
                count++;
            }else{
                if(numbers[i+1]==numbers[i]){//两者相等则不连续
                    return false;
                }//差-1即两数字间空缺数字的数量
                diff+=numbers[i+1]-numbers[i]-1;
            }
        }
        if(diff<=count)//若空缺数字的数量小于大小王的个数
            return true;
        return false;

    }
    //快速排序
    public void quickSort(int a[],int low,int high){
        if(low<high){
            int index=partition(a,low,high);
            quickSort(a,low,index-1);
            quickSort(a,index+1,high);
        }
    }
    public int partition(int a[],int low,int high){
        int temp=a[low];
        while(low<high){
            while(low<high && a[high]>temp)
                high--;
            a[low]=a[high];
            while(low<high && a[low]<temp)
                low++;
            a[high]=a[low];
        }
        a[low]=temp;
        return low;
    }
}

2.找出最大最小值,计算差值:

public class Solution {
    public boolean isContinuous(int [] numbers) {
        //大、小王=任意数字 A=1 J=11 Q=12 K=13  可以认为大小王是0
        //5张牌 可能是无序的
        if(numbers.length<1)
            return false;
        int count=0;//大小王的数量
        int max=-1;
        int min=14;
        int a[]=new int[5];//存储已出现的数字
        int j=0;
        for(int i=0;i<numbers.length;++i){
            if(numbers[i]==0){
                count++;
            }else{
                //遍历查看该数字是否已出现过
                for(int k=0;k<5;++k){
                    if(a[k]==numbers[i])//已出现则返回false
                        return false;
                }
                if(numbers[i]<min)
                    min=numbers[i];
                if(numbers[i]>max)
                    max=numbers[i];
                a[j]=numbers[i];
                j++;
            }

        }
        int diff=max-min-(numbers.length-count-1);
        return diff<=count;
    }

}

47.圆圈中最后剩下的数

0,1,…,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字,求出这个圆圈里剩下的最后一个数字。

约瑟夫环。找到规律然后递归/循环;利用循环链表

\[约瑟夫环的公式: f(n,m)= \begin{cases} 0, &n=1\\ [f(n-1,m)+m]\%n, &n>1 \end{cases} \]


1.循环:

public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        //约瑟夫环
        if(n<=0 || m<=0)//错误输入
            return -1;
        int last=0;
        for(int i=2;i<=n;++i){//公式
            last=(last+m)%i;
        }
        return last;
    }
}

2.递归:

public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        //约瑟夫环
        if(n<=0 || m<=0)//错误输入
            return -1;
        if(n==1)
            return 0;
        return (LastRemaining_Solution(n-1,m)+m)%n;
    }
}

3.循环链表:

数组模拟环。考虑每个变量的作用,考虑环如何表达等因素。

public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        //约瑟夫环
        //错误输入
        if(n<=0 || m<=0)
            return -1;
        int temp[]=new int[n];//辅助数组,存储元素
        int i=-1,step=0,count=n;//i为索引,step为走的步数(m),count为剩余的数量
        while(count>0){
            i++;
            if(i>=n)//模拟环,当到达末尾时,从头开始
                i=0;
            if(temp[i]==-1)//若为-1,证明已删除
                continue;
            step++;
            if(step==m){//走了m步,删除该元素(置-1),总数减一,步数重置为0
                temp[i]=-1;
                step=0;
                count--;
            }
        }

        return i;//返回跳出循环时i的值,即最后一个数字的索引
    }
}

48.求1+2+3…+n

求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A ? B:C)。

当这些操作不可用时,可以考虑短路操作当作递归退出条件。


短路+递归:

&&||都可以

public class Solution {
    public int Sum_Solution(int n) {
        //利用短路操作 &&
        int sum=n;
        boolean flag=(n>0)&& ((sum+=Sum_Solution(n-1))>0);//若n小于等于0则不进行后面的操作
        return sum;
    }
}

49.不用加减乘除做加法

写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

利用位运算。其中异或得到没有进位时的和,得到都为1的位,与左移一位得到进位,最后相加(直到没有进位时)得到和。


1.位运算:

public class Solution {
    public int Add(int num1,int num2) {
        //三步走 先得到不进位的结果,然后得到进位,最后相加
        if(num1==num2)//相等则左移一位 即*2
            return num1<<1;

        while(num2!=0){//若仍存在进位,继续进行运算
            int p1=num1^num2;//step 1 异或运算得到没有进位时的和
            int p2=(num1&num2)<<1;//step 2  与运算找到都为1的位,然后左移一位得到进位
            num1=p1;
            num2=p2;
        }
        return num1;
    }
}

50.把字符串转换成整数

将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0

输入描述:输入一个字符串,包括数字字母符号,可以为空

输出描述:如果是合法的数值表达则返回该数字,否则返回0

遍历,依次相加组成结果。中间需要注意越界,符号等因素


1.遍历:

public class Solution {
    public int StrToInt(String str) {
        if(str==null || str.equals("")||str.equals(" "))//异常输入
            return 0;
        str=str.trim();//去首尾空格
        boolean flag=true;//正负标志
        if(str.charAt(0)=='-'){
            flag=false;
            str=str.substring(1,str.length());
        }else if(str.charAt(0)=='+'){
            str=str.substring(1,str.length());
        }
        long res=0;//long表达,防止越界
        for(int i=0;i<str.length();++i){
            char c=str.charAt(i);
            if(c<48 || c>57)//若不是纯数字
                return 0;
            res+=(c-'0')*Math.pow(10,str.length()-i-1);//转化为整型
        }

        if(!flag){//添加符号
            res= -res;
        }

        if(res>Integer.MAX_VALUE || res<Integer.MIN_VALUE)//判断是否越界
            return 0;

        return  (int)res;

    }
}

如有错误,欢迎指正

posted @ 2020-04-15 12:20  雨落成尘  阅读(153)  评论(0编辑  收藏  举报