数据结构和算法自我学习[0410]

194 阅读5分钟

今天的题目有

  • 数组
    • 求一个数组中的第 k 小 / 大的数
    • 求所有子数组的和的最大值。
  • 字符串
    • 输入一个字符串,输出该字符串中字符的所有组合。
    • 字符串的排列问题,例如"abc"可以排多少个出来
    • 给定一个字符串,请你将字符串重新编码,将连续的字符替换成“连续出现的个数+字符”。比如字符串AAAABCCDAA会被编码成4A1B2C1D2A。(来源网易游戏笔试)
  • 链表
    • 反转链表(递归实现)

总结

  • 快速排序的思路从后往前找到小于基准(即是说明等于是不满足的,前面也是)
  • 递归:要明白每个变量代表的是什么,三部法:函数的作用、结束的条件、循环体
  • 字符串组合使用树的方式进行思考(每个元素取或不取)
  • 类型转行
    • 注意:不要对char[] chars 使用 chars.toString() 转为String类型。char的包装类:Character
    • String str -> char[] chars : chars = str.toCharArray();
    • char[] chars -> String str : str = String.valueOf(chars);
    • char chars[i] -> String str : str = String.valueOf(chars[i]);
  • 获取输入使用Scanner sc = new Scanner(System.in); String str = sc.next();

数组

求一个数组中的第 k 小 / 大的数

/**
     * 5. 题目:求一个数组中的第 k 小 / 大的数
     * 分析:使用快速排序,并且把重复的去掉
     * <p>
     * 注意:因为后段代码去重是判断i-1位是否不一样,需要返回的是i-1
     */
    public static int singleNum(int[] array, int K) {
        if (K < 1) {
            return -1;
        }
        quickSort(array, 0, array.length - 1);
        System.out.println(Arrays.toString(array));
        
        //去重
        if (K == 1) {
            return array[array.length - 1];
        }
        //先判断次数是否为1,为1直接返回,不然继续。
        //从后往前找,若找到不同的值就count进行+1,并且判断是否等于K,等于就返回,不等于继续。
        //最终没有就放回-1
        int count = 1;
        for (int i = array.length - 1; i >= 0; i--) {
            if (array[i] == array[i - 1]) {
                //相同的值不用计数,直接下一轮
                continue;
            } else {
                count++;
                if (count == K) {
                    return array[i - 1];
                }
            }
        }
        return -1;
    }

    public static int[] quickSort(int[] array, int low, int high) {
        if (array == null) {
            return null;
        }
        int start = low;
        int end = high;
        int base = array[start];
        //进行一轮的排序
        //从后往前找,比left小的数
        while (end > start) {
            while (start < end && array[end] >= base) {
                //找到为止
                end--;
            }
            if (array[end] < base) {
                //进行位置交换
                int temp = array[start];
                array[start] = array[end];
                array[end] = temp;
            }
            //找比基准大的数
            while (start < end && array[start] < base) {
                start++;
            }
            if (array[start] >= base) {
                //进行位置交换
                int temp = array[end];
                array[end] = array[start];
                array[start] = temp;
            }
        }
        //再把各自剩下的进行递归,但首先得start和end还再这个数组内
        if (start > low) {
            quickSort(array, low, start - 1);
        }
        if (end < high) {
            quickSort(array, end + 1, high);
        }
        return array;
    }

求所有子数组的和的最大值。

/**
     * 6. 题目:求所有子数组的和的最大值。
     * 思路:f(i)代表是当前从0到i的集合中 最大数的子集合
     * 当i=0或者f(i-1)<=0时,f(i)=pDate[i];当i!=0并且f(i-1)>0时,f(i)=f(i-1)+pData[i]
     * 公式的意义:前面的为负数的情况,f(i)取当前i最大,不是负数取两和为最大。
     * 具体代码实现:使用到了Math.max
     *
     * @param array
     * @return
     */
    public static int FindGreatestSumOfSubArray(int[] array) {
        if (array == null) {
            return -1;
        }
        //当前最大的子集合的结果大小
        int res = array[0];
        //到i为止的集合 的最大子集合
        int max = array[0];
        for (int i = 1; i < array.length; i++) {
            max = Math.max(max + array[i], array[i]);
            res = Math.max(res, max);
        }
        return res;
    }

字符串

输入一个字符串,输出该字符串中字符的所有组合。

/**
     * 1. 题目:字符串所有组合
     * 分析:看成树结构,每次都是要和不要的问题。
     * 注意点:递归是传count + 1,传前++和后++都是错误的
     * String str -> char[] chars : chars = str.toCharArray();
     * char[] chars -> String str : str = String.valueOf(chars);
     * char chars[i] -> String str : str = String.valueOf(chars[i]);
     * @param str
     */
    private static void printAllSubString(String str) {
        //进行判空
        if (str == null || str == "") {
            System.out.println("不存在子字符串");
            return;
        }
        char[] chars = str.toCharArray();
        String currentStr = new String("");
        printAllSubString(0, currentStr, chars);


    }

    private static void printAllSubString(int count, String currentStr, char[] chars) {
        if (count == chars.length) {
            System.out.println(currentStr);
            return;
        }
        printAllSubString(count + 1, currentStr + String.valueOf(chars[count]), chars);
        printAllSubString(count + 1, currentStr, chars);

    }

字符串的排列问题,例如"abc"可以排多少个出来

/**
     * 2. 题目:字符串的排列问题,abc可以排多少个出来
     * 两个错误: String.valueOf(chars);和在if后需加return
     * 思路:递归
     * @param str
     * @return
     */
    public static ArrayList<String> Permutation(String str) {
        if(str == null || str == ""){
            return null;
        }
        List<String> list = new ArrayList<>();
        char[] chars = str.toCharArray();
        Permutation(0, list, chars);

        return (ArrayList) list;
    }

    public static void Permutation(int i, List list, char[] chars) {
        if(i == chars.length - 1) {
            String str = String.valueOf(chars);
            if(!list.contains(str)){
                list.add(str);
            }
            return;
        }
        for(int j=i; j<chars.length; j++){
            swap(chars, i, j);
            Permutation(i+1, list, chars);
            swap(chars, i, j);
        }
    }

    public static void swap(char[] chars, int i, int j){
        char temp = chars[i];
        chars[i] = chars[j];
        chars[j] = temp;
    }

给定一个字符串,请你将字符串重新编码,将连续的字符替换成“连续出现的个数+字符”。比如字符串AAAABCCDAA会被编码成4A1B2C1D2A。

/**
     * 3. 题目:给定一个字符串,请你将字符串重新编码,将连续的字符替换成“连续出现的个数+字符”。比如字符串AAAABCCDAA会被编码成4A1B2C1D2A。
     * 思路:这题用i和i-1判断,不用i和i+1,最后还需要对i等于末尾的时候输出一下。
     * 注意点:获取输入使用Scanner sc = new Scanner(System.in); String str = sc.next();
     */
    public static void recodeToString(){
        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        char[] chars = str.toCharArray();
        if (chars.length <= 1){
            if (chars.length == 1){
                System.out.print(1+""+chars[0]);
            }
            System.out.print("");
            return;
        }

        int count = 1;
        for (int i = 1; i < chars.length; i++) {
            if (chars[i] == chars[i - 1]) {
                //说明计数+1
                count++;
            } else {
                //遇到不等的情况
                System.out.print(count);
                System.out.print(chars[i-1] + "");
                count = 1;
            }
            if (i== chars.length-1) {
                System.out.print(count);
                System.out.print(chars[i] + "");
            }
        }
    }

链表

反转链表(递归实现)

/**
     * 题目:反转链表
     * 总体:判定函数的作用,结束条件,写循环,再结束条件。
     * 递归的一种思路。
     * 递归:假设先运行,那么经过出口后,会有需要进行处理的,这个时候就处理最终的结果。
     * @param head
     * @return
     */
    public ListNode ReverseList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        //假设进行递归调用,currentNode代表的是原链表的最后一个
        ListNode newNode = ReverseList(head.next);
        head.next.next = head;
        head.next = null;
        return newNode;

    }