1305 2018-11-24 2020-06-25

前言:牛客网剑指Offer编程题43~48题。

一、左旋转字符串

1、题目描述

考点知识迁移能力,对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。

2、我的代码

static class FortyThree {
    public String LeftRotateString(String str,int n) {
        if (str == null || str.length() == 0) {
            return str;
        }
        char[] chars = str.toCharArray();
        //n = n % str.length();
        char[] temp = new char[n];
        for (int i = 0; i < n; i++) {
            temp[i] = chars[i];
        }
        for (int i = 0; i < chars.length - n; i++) {
            chars[i] = chars[i + n];
        }
        for (int i = 0; i < n; i++) {
            chars[chars.length - 1 - i]  = temp[n - 1 - i];
        }
        return String.valueOf(chars);
    }
}

3、别人的代码

剑指Offer上面提供的解答是三次翻转,具体思路如下:假设给定提交abcdefg 3,那么首先翻转abcdefg为cbadefg,然后再翻转cbadefg为cbagfed,最后翻转所有得defgabc。思路巧是巧妙,学习一下吧。

public String LeftRotateString(String str,int n) {
    char[] chars = str.toCharArray();        
    if(chars.length < n) return "";
    reverse(chars, 0, n-1);
    reverse(chars, n, chars.length-1);
    reverse(chars, 0, chars.length-1);
    StringBuilder sb = new StringBuilder(chars.length);
    for(char c:chars){
        sb.append(c);
    }
    return sb.toString();
}

public void reverse(char[] chars,int low,int high){
    char temp;
    while(low<high){
        temp = chars[low];
        chars[low] = chars[high];
        chars[high] = temp;
        low++;
        high--;
    }
}

二、翻转单词顺序列

1、题目描述

考点知识迁移能力,例如,“student. a am I”,翻转单词顺序使其为“I am a student.”。

2、我的代码

还是用上面的思想

static class FortyFour {
    public String ReverseSentence(String str) {
        if (str == null || str.length() == 0 || !str.contains(" ")) {
            return str;
        }
        char[] chars = str.toCharArray();
        reverse(chars, 0, chars.length - 1);
        int begin = 0, end = 0;
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == ' ') {
                end = i;
                reverse(chars, begin, end - 1);
                begin = end + 1;
            }
        }
        if (begin == end + 1) {
            reverse(chars, begin, chars.length - 1);
        }
        return String.valueOf(chars);
    }

    private void reverse(char[] chars, int start, int end) {
        char temp;
        while (start < end) {
            temp = chars[start];
            chars[start] = chars[end];
            chars[end] = temp;
            start++;
            end--;
        }
    }
}

三、扑克牌顺子

1、题目描述

考点抽象建模能力,大\小王可以看成任何数字,并且A看作1,J为11,Q为12,K为13,且为了方便起见,你可以认为大小王是0(有两个大小王),判断输入的5个数是否为顺子。

2、我的代码

static class FortyFive {
    public boolean isContinuous(int [] numbers) {
        if (numbers.length != 5) {
            return false;
        }
        quickSort(numbers, 0, numbers.length - 1);
        if (numbers[0] != 0) {
            for (int i = 0; i < numbers.length - 1; i++) {
                if (numbers[i] + 1 != numbers[i + 1]) {
                    return false;
                }
            }
            return true;
        } else {
            int kingCount = 0;
            for (int i = 0; i < numbers.length - 1; i++) {
                if (numbers[i] == 0) {
                    kingCount++;
                }
            }
            for (int i = kingCount; i < numbers.length - 1; i++) {
                if (numbers[i] == numbers[i + 1]) {
                    return false;
                }
            }
            int needValue = 0;
            for (int i = numbers.length - 1; i > kingCount; i--) {
                int temp = numbers[i] - numbers[i - 1];
                if (temp != 1) {
                    needValue += temp - 1;
                }
            }
            if (kingCount < needValue) {
                return false;
            } else {
                return true;
            }
        }
    }

    private void quickSort(int[] nums, int start, int end) {
        if (start >= end || start < 0 || end > nums.length - 1) {
            return;
        }
        int index = start;
        for (int i = start; i <= end; i++) {
            if (nums[i] < nums[index]) {
                int temp = nums[i];
                for (int j = i; j > start; j--) {
                    nums[j] = nums[j - 1];
                }
                nums[start] = temp;
                index++;
            }
        }
        quickSort(nums, start, index - 1);
        quickSort(nums, index + 1, end);
    }

    private static void test() {
        int[] arr = {5, 4, 3, 2, 1, 8, 7, 6, 9};
        new FortyFive().quickSort(arr, 0, arr.length - 1);
        for (int i : arr) {
            System.out.println(i);
        }
    }
}

四、圆圈中最后剩下的数

1、题目描述

考点抽象建模能力,0, 1, ..., n - 1这几个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈剩下的最后一个数字。

2、我的代码

static class FortySix {
    public int LastRemaining_Solution(int n, int m) {
        if (n <= 0 || m <= 0) {
            return -1;
        }
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            list.add(i);
        }
        int cur = 0;
        while (list.size() != 1) {
            cur += m - 1;
            while (cur > list.size() - 1) {
                cur = cur - list.size();
                System.out.println("返回头坐标" + cur);
            }
            int r = list.remove(cur);
            System.out.println("移除" + r + "通过位置" + cur);
        }
        return list.get(0);
    }

    private static void test() {
        int result = new FortySix().LastRemaining_Solution(5, 3);
        System.out.println(result);
    }
}

五、求1+2+3+...+n

1、题目描述

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

2、我的代码

感觉是有点违背题目要求了。

public int Sum_Solution(int n) {
    if (n == 0) {
        return 0;
    }
    return Sum_Solution(n - 1) + n;
}

3、别人的代码

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

聪明人还是多啊。

六、不用加减乘除做加法

1、题目描述

考点思维发散能力,写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

2、别人的代码

一看到这个题目,我第一反应就是为运算,但看了许久,也不是很懂。

首先看十进制是如何做的: 5+7=12,三步走
第一步:相加各位的值,不算进位,得到2。
第二步:计算进位值,得到10. 如果这一步的进位值为0,那么第一步得到的值就是最终结果。

第三步:重复上述两步,只是相加的值变成上述两步的得到的结果2和10,得到12。

同样我们可以用三步走的方式计算二进制值相加: 5-101,7-111 第一步:相加各位的值,不算进位,得到010,二进制每位相加就相当于各位做异或操作,101^111。

第二步:计算进位值,得到1010,相当于各位做与操作得到101,再向左移一位得到1010,(101&111)<<1。

第三步重复上述两步, 各位相加 010^1010=1000,进位值为100=(010&1010)<<1。
     继续重复上述两步:1000^100 = 1100,进位值为0,跳出循环,1100为最终结果。

public class Solution {
    public int Add(int num1,int num2) {
        while (num2!=0) {
            int temp = num1^num2;
            num2 = (num1&num2)<<1;
            num1 = temp;
        }
        return num1;
    }
}    

3、别人的代码2

我比较喜欢这种,人才啊。

public int Add(int num1,int num2) {
    if(num1>0){
        while(num1--!=0)
            num2++;
    }
    else if(num1<0){
        while(num1++!=0)
            num2--;
    }
    return num2;
}

一天6道题完工。

总访问次数: 316次, 一般般帅 创建于 2018-11-24, 最后更新于 2020-06-25

进大厂! 欢迎关注微信公众号,第一时间掌握最新动态!