剑指offer_抽象建模-发散思维-综合


前言:当前内容只用来回忆复习,java编写,代码尽可能带注释,部分题目附上解题思路。如有错误,请指出,谢谢。

感悟:刷题重在思路以及巩固知识点,而不是刷题进度。

重点:位运算,异或实现无进位加法,与运算找出需要进位的位置

1、扑克牌顺子

题目描述
LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张_)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。

1.1 类似哈希数组的思想,数组下标作为键,数组内容作为值

public class Solution {
    public boolean isContinuous(int [] numbers) {
        // 数组中应该有5个数,表示5张牌,否则false
        if(numbers == null || numbers.length != 5)
            return false;
        // 若没有大小王,就不能任意替代,那么剩下的数字必须是顺子,最大最小值差为4
        // 若存在大小王,认为0,存在替代可能,那么,差值不能超过5,否则无法弥补中间缺的数字
        // 结论:1、非0数字不能重复,2、非0个数的差值不能超过5,即小于5,
        // 3、0的个数就是大小王的个数,<=4, 4、输入的数范围为0-13的整数
        int[] arr = new int[14]; // 每一索引对应一个数字,存放的值就是出现次数
        for(int i = 0; i < 5; i++){
            int pos = numbers[i];
            if(pos < 0 || pos >13)
                return false; // 去除在0-13外的情况
            arr[pos]++; // 存入出现次数
            // 非0次数的判断,去重
            if(pos > 0 && arr[pos] > 1)
                return false; // 如果非0数字出现超过1次,那么肯定不是顺子
            // 0数字,万能数字,次数的判断,<=4
            if(pos == 0 && arr[pos] > 4)
                return false; // 如果万能数字超过4次,那么肯定出错
        }
        // 非0数字至少有一个,因为最多4个王
        // 非0数字1-13, 1个或超过1个,最大最小值的差必须小于5,
        int min = 14;
        int max = 0;
        for(int pos = 1; pos <= 13; pos++){
            if(arr[pos] != 0){
                min = pos < min ? pos : min;
                max = pos > max ? pos : max;
            }
        }
        if((max-min) >= 5)
            return false; 
        return true;
    }
}

1.2 将数组排序

import java.util.Arrays;
public class Solution {
    public boolean isContinuous(int [] numbers) {
        // 数组中应该有5个数,表示5张牌,否则false
        if(numbers == null || numbers.length != 5)
            return false;
        // 若没有大小王,就不能任意替代,那么剩下的数字必须是顺子,最大最小值差为4
        // 若存在大小王,认为0,存在替代可能,那么,差值不能超过5,否则无法弥补中间缺的数字
        // 结论:1、非0数字不能重复,2、非0个数的差值不能超过5,即小于5,
        // 3、0的个数就是大小王的个数,<=4, 4、输入的数范围为0-13的整数
        for(int i = 0; i < 5; i++){
            int val = numbers[i];
            if(val < 0 || val > 13)
                return false;
        }
        Arrays.sort(numbers); // 排序后,最后一个肯定是非0数字的最大值,顺序遍历找到第一个不为0的数字即为非0最小值
        int pos = 0;
        while(numbers[pos] == 0){
            pos++;
        }
        if(pos > 4)
            return false; // 大小王总数超过4,说明错误
        // 将所有非0的数遍历,如果有重复的数, 或是两数之差>=5,输出false
        for(int j = pos; j<numbers.length-1; j++) 
        {
            if(numbers[j] == numbers[j+1]) 
                return false;
            if(numbers[j+1]-numbers[pos]>=5) 
                return false;
        }
        return true;
    }
}

2、孩子们的游戏

题目描述
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数…这样下去…直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!_)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)

如果没有小朋友,请返回-1

2.1

在这里插入代码片

3、求1+2+3+…+n

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

3.1 与逻辑的短路特性可以作为递归结束条件

public class Solution {
    public int Sum_Solution(int n) {
        //n <= 0 是退出循环条件
        // 这里n为负值返回自身
        boolean flag = (n > 0) && ((n += Sum_Solution(n-1) ) > 0 );
        return n;
    }
}

4、不用加减乘除做加法

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

4.1 异或运算 配合 与运算 实现加法

public class Solution {
    public int Add(int num1,int num2) {
        // 不能用传统的四则运算实现加法,那就只有最底层的位运算了
        // 异或实现的是无进位加法, 与运算可以找出进位
        int sum = num1 ;
        int add = num2 ;
        while(add != 0){
            int tmp = sum ^ add; // 保存无进位加法结果
            add = (sum & add ) << 1; // 保存进位条件,若判断当前位置同为1,那么需要在当前位置的高一位进位
            sum = tmp;
        }
        return sum;
    }
}

5、把字符串转换成整数

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

输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0

示例1

输入:
+2147483647
    1a33

输出:
2147483647
    0

5.1 主要关注点在整形溢出

public class Solution {
    public int StrToInt(String str) {
        // 排除空指针问题
        if(str == null || str.length() == 0)
            return 0;
        // 只有在字符串头加上+-号,以及字符创中不能出现非数字字符才能转为数字 
        int flag = 1; // 默认是正数,因为负数,字符串头必须要加—号,正数可以加+或不加+
        // 有可能出现数字溢出的情况
        int sum = 0; // 设置初始值
        for(int i = 0; i < str.length(); i++){
            // 判断符号位
            if(i ==0 && str.charAt(i) == '-'){
                flag = -1;
                continue;
            }
            if(i == 0 && str.charAt(i) == '+'){
                continue;
            }
            if(str.charAt(i) < '0' || str.charAt(i) > '9')
                return 0; // 存在非法字符直接返回
            // 数字溢出情况, 数字溢出就是超出了边界,如果为正数,sum不能超过Int的最大值
            // 若为负数,sum不能超过Int的最小值的绝对值
            int tmp = sum;
            int cur = str.charAt(i) - '0';
            sum = (sum * 10 + cur);
            if(flag == 1 && tmp >= Integer.MAX_VALUE/10 && cur >7){
                return 0;
            }
            if(flag == -1 && tmp >= Integer.MAX_VALUE/10 && cur > 8 ){
                return 0;
            }
        }
        return flag * sum;
    }
}

疑惑?

这题的结果,竟然能出现超过整数的最小值Integer.MIN_VALUE,如-2147483649情况,是不是哪里有问题?
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值