剑指offer之每日6题 ----- 第八天

原题链接

1.左旋转字符串

题目描述

汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

思路

第一步:将字符序列分隔成两个子字符串s1=abc,s2=XYZdef
第二步:分别翻转这两个子字符串,结果为st1=cba,st2=fedZYX
第三步:再对整个序列进行翻转,即对cbafedZYX,进行翻转,结果为XYZdefabc

public String leftRotateString(String str,int n) {
        if (str.length() < n)
            return "";
        char[] chars = str.toCharArray();
        reverse(chars,0,n-1);
        reverse(chars,n,str.length()-1);
        reverse(chars,0,str.length()-1);

        StringBuilder sb = new StringBuilder();
        for (char c : chars) {
            sb.append(c);
        }
        return sb.toString();
    }
    private void reverse(char[] chars,int start,int end){

        while (start < end){
            char temp = chars[start];
            chars[start] = chars[end];
            chars[end] = temp;

            start++;
            end--;
        }
    }

2.翻转单词顺序列

题目描述

牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

思路

第一步:将整个句子进行翻转,即得到 I ma a tneduts
第二步:将句子里面的每个字符进行翻转I am a student
这种思路的写法同第一题差不多,只需要找到起始和末尾位置即可,可以用是否是空格来判断,这就不提供代码。这个还有一种解法
解法的思路是将每个单词分别存放在数组,最后倒着遍历一遍,即是正确顺序的句子,代码如下:

   public String reverseSentence(String str) {
        if (str == null ){
            return null;
        }
        if (str.trim().equals("")){
            return str;
        }
        String[] split = str.split(" ");
        StringBuilder sb= new StringBuilder();

        for (int i = split.length-1; i >= 0; i--) {
            if (i ==0){
                sb.append(split[i]);
            }else{
                sb.append(split[i]);
                sb.append(" ");
            }
        }
        return sb.toString();
    }

3.扑克牌顺子

题目描述

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 对数组进行排序,找出排序数组中相邻来两个数之间的空缺
2 找出数组中0的数量
3 如果0的数量 >= 空缺 则是顺子,否则就不是顺子
4 如果是有对子,就不算顺子

    public boolean isContinuous(int[] numbers) {
        if (numbers == null)
            return false;
        if (numbers.length == 0)
            return false;
        //排序
        Arrays.sort(numbers);
        int numberOf0 = 0; int numberOfGap = 0;
        //统计0的个数
        for (int i = 0; i < numbers.length && numbers[i] == 0; i++) {
            numberOf0++;
        }
        for (int i = numberOf0 ; i < numbers.length - 1; i++) {
            //有对子,则不是
            if (numbers[i] == numbers[i + 1])
                return false;
            numberOfGap += numbers[i + 1] - numbers[i] - 1;
        }
        return numberOfGap > numberOf0 ? false : true;
    }

4.孩子们的游戏

题目描述

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

思路

这道题经典解法就是用环形链表来模拟圆圈的数字,环形链表就是每当扫描到最后一个节点的时候,将指针移动到链表的头部。
还可以去计算出每次要删除的位置,网上有很多那个数学的推导公式,原谅我数学不太好推不太清楚,我就按照自己的方法,计算出每次要删除的位置,然后删除即可

 public int lastRemaining_Solution(int n, int m) {
        if (n < 1 || m <1)
            return -1;
        LinkedList<Integer> list = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            list.add(i);
        }
        //每次删除第m个数字之后的起始位置
        int index = 0;
        while (list.size() > 1){
            //第一次被删除的位置是(m-1)% n
            int delPos = (index + m -1) % list.size();
            list.remove(delPos);
            index=delPos % list.size();
        }
        return list.get(0);
    }

5.求1+2+3+…+n

题目描述

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

思路

递归,当n==0时候,flag为false,直接返回0
当 n>0时候,执行sum+=Sum_Solution(n - 1);

public int sum_Solution(int n) {
        int sum = n;
        boolean flag =(n > 0 && (sum+=Sum_Solution(n - 1)) > 0);
        return sum;
}

6.不用加减乘除做加法

题目描述

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

思路

在十进制中进行加法运算,有三步,第一步只对各个位相加不作进位,第二步得出进位,第三步将第一步和第二步结果相加。比如5+17,第一步结果12,第二步进位是10,第三步结果是12+10=22
同样在二进制中,也是同样的三步,5的二进制是101,17的二进制是10001
第一步,只相加不进位,结果10100
第二步,记下进位,就是10
第三步,将第一步和第二步相加,结果是10110
看出第一步中0+0=1,0+1=1,1+1=0,这也就是位运算的异或运算
第二步进位计算,只有在1+1的时候才产生进位,然后将结果左移一位,只有在位与运算的时候,1 & 1=1,其他与运算结果都是0

   public int add(int num1, int num2) {
        int sum, carry;
        do {
            sum = num1 ^ num2;
            carry = (num1 & num2) << 1;
            num1 = sum;
            num2 = carry;
        } while (num2 != 0);
        return num1;
    }

猜你喜欢

转载自blog.csdn.net/YuQing_Cat/article/details/86492271