每日一题之《剑指offer》27,28题目

第二十七题:字符串的排列

难易度:⭐⭐⭐

输入一个字符串,按字典序打印出该字符串中字符的所有排列
例如输入字符串abc
则打印出由字符a,b,c所能排列出来的所有字符串
abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母

本题分析:
以输入的字符串为 “abc”举例:
要想求出整个字符串的排列,可以分成两步:
第一步:求出所有可能出现在第一个位置的字符,即把第一个字符和后面所有的字符交换
第二步:固定第一个字符,求出后面所有字符的排列

输入:abc

a和第一个位置的字符也就是自己发生交换  abc
对于a后面的字符串 bc递归这样一个过程

a和第二个位置的字符b发生交换  bac 
对于b后面的字符串ac递归这样一个过程

a和第三个位置的字符c发生交换  cba
对于c后面的字符串ba递归这样一个过程

这样求解后,得到了字符串的全排列,但是并不是按照字典序进行排序的顺序,所以还需要对所有的字符串进行排序,才可以返回结果。
本题我只想到了这样一种思路,二刷的时候,会想想有没有更好的解决办法
代码如下:

import java.util.Collections;
import java.util.ArrayList;
public class Solution {
    public ArrayList<String> Permutation(String str) {
        
        ArrayList<String> arrayList = new ArrayList<>();
        
        if(str.length() == 1){
            arrayList.add(str);
            return arrayList;
        }
        
        for(int i = 0; i < str.length(); i++){
            if(i == 0 || str.charAt(i) != str.charAt(0)){
                String temp = swap(str,0,i);
                String childStr = temp.substring(1);
                ArrayList<String> tempList = Permutation(childStr);
                for(String s : tempList){
                    arrayList.add(temp.charAt(0) + s);
                }
            }
        }
        Collections.sort(arrayList);
        return arrayList;
    }

    public static String swap(String str,int i,int j){
        if(i == j){
            return str;
        }
        char tempI = str.charAt(i);
        char tempJ = str.charAt(j);
        StringBuilder sb = new StringBuilder(str);
        sb.setCharAt(i,tempJ);
        sb.setCharAt(j,tempI);
        return sb.toString();
    }
}

第二十八题:数组中出现次数超过一半的数字

难易度:⭐

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字
例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}
由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2
如果不存在则输出0

本题虽然非常简单,但是我觉得这道题真的非常好。
先说一下,我看到这道题目最先想到的思路吧:

思路一:

不难想到,利用HashMap,遍历一遍数组以后,key存数组的值,value存,这个值在数组中出现的个数,在更新value的时候,取判断当前的value是否超过了arr.length/2。当然,这种思路是我未加思考的结果,还是把代码奉上,任凭大家吐槽:

import java.util.HashMap;
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int i = 0;i < array.length;i++){
            if(map.containsKey(array[i])){
                int temp = map.get(array[i]);
                map.put(array[i],++temp);
                if(isMoreThanHalf(array,temp)){
                    return array[i];
                }
            }else{
                map.put(array[i],1);
                if(isMoreThanHalf(array,map.get(array[i]))){
                    return array[i];
                }
            }
        }
        return 0;
    }
    
    public static boolean isMoreThanHalf(int[] arr,int num){
        return num > arr.length >> 1;
    }
}

思路二:

上面的代码使用了多余的数据结构HashMap,如何能够不使用任何数据结构,仅在O(n)的时间复杂度下完成这样的需求呢?
仔细想一想:
一个数组中,一个数字出现的次数如果超过数组长度的一半,那么经过排序后,这个数字一定位于数组的中间
如,对于数组:

1,1,3,1,5

排序后:

1,1,1,3,5

1出现的次数为3 超过了数组长度的一半 2,那么排序后的这个数一定会在数组的最中间!
有了这样一个结论,我们不难写出代码:

import java.util.Arrays;
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        if(array == null || array.length == 0){
            return 0;
        }
        Arrays.sort(array);
        int target = array[array.length >> 1];
        int count = 0;
        for(int i = 0;i < array.length; i++){
            if(array[i] == target){
                count++;
                if(isMoreThanHalf(count,array)){
                    return target;
                }
            }
        }
        return isMoreThanHalf(count,array)? target:0;
    }
    public static boolean isMoreThanHalf(int count,int[] array){
        return count > array.length >> 1;
    }
}

但是,这样做又会强行将算法变为O(nlogn)的时间复杂度,本题的最优解应该是O(n)级别的算法:
本思路是我在牛客网本题下的评论区看到的,觉得非常妙:

思路三:

如果有符合条件的数字,则它出现的次数比其他所有数字出现的次数和还要多
采用阵地攻守的思想:
第一个数字作为第一个士兵,守阵地 count = 1;
遇到相同元素,则count++;
遇到不同的元素,即为敌人,同归于尽,count--;
又以新的i值作为守阵地的士兵继续下去,到最后还留在阵地上的士兵,有可能是主元素。
再加一次循环,记录这个士兵的个数看是否大于数组一般即可

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        if(array == null || array.length == 0){
            return 0;
        }
        int target = array[0];
        int count = 1;
        for(int i = 1;i < array.length;i++){
            if(count == 0){
                target = array[i];
                count = 1;
            }else if(array[i] == target){
                count++;
            }else{
                count--;
            }
        }
        count = 0;
        for(int i = 0;i < array.length;i++){
            if(array[i] == target){
                count++;
            }
        }
        return count > array.length >> 1 ? target : 0;
    }
}
全部评论

相关推荐

钱嘛数字而已:辅导员肯定不能同意,不然你出事了,他要承担责任。但是,脚和脑子都长在你自己身上,使用它还需要向辅导员报告么? 辅导员必须按流程拒绝你,然后你拿出成年人的态度,做自己的选择。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
正在热议
更多
# 春招至今,你的战绩如何? #
4734次浏览 44人参与
# 你的实习产出是真实的还是包装的? #
1093次浏览 27人参与
# 巨人网络春招 #
11132次浏览 221人参与
# 军工所铁饭碗 vs 互联网高薪资,你会选谁 #
6891次浏览 36人参与
# 简历第一个项目做什么 #
31243次浏览 312人参与
# 当下环境,你会继续卷互联网,还是看其他行业机会 #
186328次浏览 1114人参与
# MiniMax求职进展汇总 #
22842次浏览 293人参与
# 面试紧张时你会有什么表现? #
30317次浏览 188人参与
# 简历中的项目经历要怎么写? #
309349次浏览 4149人参与
# 网易游戏笔试 #
6302次浏览 83人参与
# 职能管理面试记录 #
10676次浏览 59人参与
# 把自己当AI,现在最消耗你token的问题是什么? #
6843次浏览 154人参与
# 从哪些方向判断这个offer值不值得去? #
56694次浏览 357人参与
# 腾讯音乐求职进展汇总 #
160388次浏览 1105人参与
# 小红书求职进展汇总 #
226842次浏览 1356人参与
# AI时代,哪些岗位最容易被淘汰 #
62336次浏览 725人参与
# 你怎么看待AI面试 #
179242次浏览 1162人参与
# 正在春招的你,也参与了去年秋招吗? #
362478次浏览 2631人参与
# 你的房租占工资的比例是多少? #
92122次浏览 896人参与
# 机械求职避坑tips #
94395次浏览 567人参与
# 校招笔试 #
466042次浏览 2950人参与
# 面试官最爱问的 AI 问题是...... #
27078次浏览 834人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务