美文网首页
阿俊带你用Kotlin刷算法(二)

阿俊带你用Kotlin刷算法(二)

作者: 谭嘉俊 | 来源:发表于2021-06-19 21:50 被阅读0次

    本系列通过JavaKotlin这两种语言来解决力扣上面的算法题,由于本人算法菜鸟一枚,可能部分题目并不是最优题解,希望能和各位大神共同讨论~

    阿俊带你用Kotlin刷算法(一)

    阿俊带你用Kotlin刷算法(二)

    项目的GitHub:Algorithm

    寻找两个正序数组的中位数(Median of Two Sorted Arrays)

    难度:困难

    链接:Median of Two Sorted Arrays

    代码

    Java

    /**
     * Created by TanJiaJun on 2021/6/9.
     * 4. 寻找两个正序数组的中位数(Median of Two Sorted Arrays)
     * 难度:困难
     *
     * @see <a href="https://leetcode-cn.com/problems/median-of-two-sorted-arrays/">Median of Two Sorted Arrays</a>
     */
    class MedianOfTwoSortedArrays {
    
        public static void main(String[] args) {
            // 示例一
            System.out.println("示例一:");
    
            int[] firstNumbers = {1, 3};
            int[] secondNumbers = {2};
            System.out.println(findMedianSortedArrays(firstNumbers, secondNumbers));
    
            System.out.print("\n");
    
            // 示例二
            System.out.println("示例二:");
    
            int[] thirdNumbers = {1, 2};
            int[] fourthNumbers = {3, 4};
            System.out.println(findMedianSortedArrays(thirdNumbers, fourthNumbers));
    
            System.out.print("\n");
    
            // 示例三
            System.out.println("示例三:");
    
            int[] fifthNumbers = {0, 0};
            int[] sixthNumbers = {0, 0};
            System.out.println(findMedianSortedArrays(fifthNumbers, sixthNumbers));
    
            System.out.print("\n");
    
            // 示例四
            System.out.println("示例四:");
    
            int[] seventhNumbers = {};
            int[] eightNumbers = {1};
            System.out.println(findMedianSortedArrays(seventhNumbers, eightNumbers));
    
            System.out.print("\n");
    
            // 示例五
            System.out.println("示例五:");
    
            int[] ninthNumbers = {2};
            int[] tenthNumbers = {};
            System.out.println(findMedianSortedArrays(ninthNumbers, tenthNumbers));
        }
    
        /**
         * 双指针
         * 时间复杂度:O(m+n),其中m是数组num1的长度,n是数组num2的长度
         * 空间复杂度:O(m+n),其中m是数组num1的长度,n是数组num2的长度
         *
         * @param firstNumbers  第一个数组
         * @param secondNumbers 第二个数组
         * @return 结果
         */
        public static double findMedianSortedArrays(int[] firstNumbers, int[] secondNumbers) {
            int len1 = firstNumbers.length;
            int len2 = secondNumbers.length;
            // 合并后的数组的索引
            int index = 0;
            // 第一个数组的指针,下面用i指针描述
            int i = 0;
            // 第二个数组的指针,下面用j指针描述
            int j = 0;
            // 合并两个数组
            // 创建一个大小是两个数组长度之和的数组
            int[] arrays = new int[len1 + len2];
            while (i < len1 || j < len2) {
                if (i == len1) {
                    // 如果第一个数组遍历完毕后,就继续遍历第二个数组
                    arrays[index++] = secondNumbers[j++];
                } else if (j == len2) {
                    // 如果第二个数组遍历完毕后,就继续遍历第一个数组
                    arrays[index++] = firstNumbers[i++];
                } else if (firstNumbers[i] < secondNumbers[j]) {
                    // 如果第一个数组的元素小于第二个数组的元素,就将第一个数组中的该元素添加到合并后的新数组,同时将i指针向右移动一格
                    arrays[index++] = firstNumbers[i++];
                } else {
                    // 如果第一个数组的元素大于第二个数组的元素,就将第二个数组中的该元素添加到合并后的新数组,同时将j指针向右移动一格
                    arrays[index++] = secondNumbers[j++];
                }
            }
            // 找出数组的中位数
            double median;
            int length = arrays.length;
            if (length % 2 == 0) {
                // 如果数组长度是偶数,就找出这条中线旁边的两个元素,然后相加之后除以2得到结果
                median = (arrays[length / 2] + arrays[length / 2 - 1]) / 2.0D;
            } else {
                // 如果数组长度是奇数,就找出这条中线对应的元素,该元素就是结果
                median = arrays[length / 2];
            }
            return median;
        }
    
    }
    

    Kotlin

    /**
     * Created by TanJiaJun on 2021/6/13.
     * 4. 寻找两个正序数组的中位数(Median of Two Sorted Arrays)
     * 难度:困难
     *
     * @see <a href="https://leetcode-cn.com/problems/median-of-two-sorted-arrays/">Median of Two Sorted Arrays</a>
     */
    object MedianOfTwoSortedArraysKotlin {
    
        @JvmStatic
        fun main(args: Array<String>) {
            // 示例一
            println("示例一:")
    
            val firstNumbers = intArrayOf(1, 3)
            val secondNumbers = intArrayOf(2)
            println(findMedianSortedArrays(firstNumbers, secondNumbers))
    
            print("\n")
    
            // 示例二
            println("示例二:")
    
            val thirdNumbers = intArrayOf(1, 2)
            val fourthNumbers = intArrayOf(3, 4)
            println(findMedianSortedArrays(thirdNumbers, fourthNumbers))
    
            print("\n")
    
            // 示例三
            println("示例三:")
    
            val fifthNumbers = intArrayOf(0, 0)
            val sixthNumbers = intArrayOf(0, 0)
            println(findMedianSortedArrays(fifthNumbers, sixthNumbers))
    
            print("\n")
    
            // 示例四
            println("示例四:")
    
            val seventhNumbers = intArrayOf()
            val eightNumbers = intArrayOf(1)
            println(findMedianSortedArrays(seventhNumbers, eightNumbers))
    
            print("\n")
    
            // 示例五
            println("示例五:")
    
            val ninthNumbers = intArrayOf(2)
            val tenthNumbers = intArrayOf()
            println(findMedianSortedArrays(ninthNumbers, tenthNumbers))
        }
    
        /**
         * 双指针
         * 时间复杂度:O(m+n),其中m是数组num1的长度,n是数组num2的长度
         * 空间复杂度:O(m+n),其中m是数组num1的长度,n是数组num2的长度
         *
         * @param nums1 第一个数组
         * @param nums2 第二个数组
         * @return 结果
         */
        private fun findMedianSortedArrays(nums1: IntArray, nums2: IntArray): Double {
            val size1 = nums1.size
            val size2 = nums2.size
            // 合并后的数组的索引
            var index = 0
            // 第一个数组的指针,下面用i指针描述
            var i = 0
            // 第二个数组的指针,下面用j指针描述
            var j = 0
            // 合并两个数组
            // 创建一个大小是两个数组长度之和的数组
            val arrays = IntArray(size1 + size2)
            while (i < size1 || j < size2) {
                when {
                    // 如果第一个数组遍历完毕后,就继续遍历第二个数组
                    i == size1 -> arrays[index++] = nums2[j++]
                    // 如果第二个数组遍历完毕后,就继续遍历第一个数组
                    j == size2 -> arrays[index++] = nums1[i++]
                    // 如果第一个数组的元素小于第二个数组的元素,就将第一个数组中的该元素添加到合并后的新数组,同时将i指针向右移动一格
                    nums1[i] < nums2[j] -> arrays[index++] = nums1[i++]
                    // 如果第一个数组的元素大于第二个数组的元素,就将第二个数组中的该元素添加到合并后的新数组,同时将j指针向右移动一格
                    else -> arrays[index++] = nums2[j++]
                }
            }
            // 找出数组的中位数
            val size = arrays.size
            return if (size % 2.0 == 0.0) {
                // 如果数组长度是偶数,就找出这条中线旁边的两个元素,然后相加之后除以2得到结果
                (arrays[size / 2] + arrays[size / 2 - 1]) / 2.0
            } else {
                // 如果数组长度是奇数,就找出这条中线对应的元素,该元素就是结果
                arrays[size / 2].toDouble()
            }
        }
    }
    

    时间复杂度:O(m+n),其中m是数组num1的长度,n是数组num2的长度。

    空间复杂度:O(m+n),其中m是数组num1的长度,n是数组num2的长度。

    题解

    根据题目可知,这两个数组都是正序(从小到大)的,所以我们可以先使用双指针将这两个数组合并成一个数组,注释写得挺详细了,这里就不在赘述了,合并后得到一个大小是两个数组长度之和的新数组,然后我们从这个数组找出中位数,有两种情况:

    • 如果数组长度是偶数,就找出这条中线旁边的两个元素,然后相加之后除以2得到结果。
    • 如果数组长度是奇数,就找出这条中线对应的元素,该元素就是结果。

    最长回文子串(Longest Palindromic Substring)

    难度:中等

    链接:Longest Palindromic Substring

    代码

    Java

    /**
     * Created by TanJiaJun on 2021/6/10.
     * 5. 最长回文子串(Longest Palindromic Substring)
     * 难度:中等
     *
     * @see <a href="https://leetcode-cn.com/problems/longest-palindromic-substring/">Longest Palindromic Substring</a>
     */
    class LongestPalindromicSubstring {
    
        public static void main(String[] args) {
            // 示例一
            System.out.print("示例一:");
    
            String firstStr = "babad";
            System.out.println(expandAroundCenterLongestPalindrome(firstStr));
    
            System.out.print("\n");
    
            // 示例二
            System.out.print("示例二:");
    
            String secondStr = "cbbd";
            System.out.println(expandAroundCenterLongestPalindrome(secondStr));
    
            System.out.print("\n");
    
            // 示例三
            System.out.print("示例三:");
    
            String thirdStr = "a";
            System.out.println(expandAroundCenterLongestPalindrome(thirdStr));
    
            System.out.print("\n");
    
            // 示例四
            System.out.print("示例四:");
    
            String fourthStr = "ac";
            System.out.println(expandAroundCenterLongestPalindrome(fourthStr));
        }
    
        /**
         * 方法一:枚举算法
         * 时间复杂度:O(N^3),其中N是字符串的长度
         * 空间复杂度:O(1)
         *
         * @param str 字符串
         * @return 结果
         */
        private static String longestPalindrome(String str) {
            int maxLength = 0;
            String result = "";
            // 枚举所有的元素
            for (int i = 0, iLen = str.length(); i < iLen; i++) {
                for (int j = i + 1, jLen = str.length(); j <= jLen; j++) {
                    String substring = str.substring(i, j);
                    if (isPalindromeSubstring(substring) && substring.length() > maxLength) {
                        maxLength = substring.length();
                        result = substring;
                    }
                }
            }
            return result;
        }
    
        /**
         * 判断字符串是否为回文串
         *
         * @param str 字符串
         * @return 结果
         */
        private static boolean isPalindromeSubstring(String str) {
            int length = str.length();
            for (int i = 0; i < length / 2; i++) {
                // 找出该元素作为回文子串的起始位置还有结束位置
                if (str.charAt(i) != str.charAt(length - i - 1)) {
                    // 如果其中一个不相同,证明该字符串不是回文串
                    return false;
                }
            }
            // 如果字符都相同,证明该字符串是回文串
            return true;
        }
    
        /**
         * 方法二:中心扩展法(双指针)
         * 时间复杂度:O(N^2),其中N是字符串的长度
         * 空间复杂度:O(1)
         *
         * @param str 字符串
         * @return 结果
         */
        private static String expandAroundCenterLongestPalindrome(String str) {
            int start = 0;
            int end = 0;
            for (int i = 0, length = str.length(); i < length; i++) {
                // 长度是奇数
                int oddLength = getExpandAroundCenterLength(str, i, i);
                // 长度是偶数
                int evenLength = getExpandAroundCenterLength(str, i, i + 1);
                // 得到最大长度
                int maxLength = Math.max(oddLength, evenLength);
                if (maxLength > end - start) {
                    // 得到起始位置
                    start = i - (maxLength - 1) / 2;
                    // 得到结束位置
                    end = i + maxLength / 2;
                }
            }
            // 截取对应的字符
            return str.substring(start, end + 1);
        }
    
        /**
         * 得到中心往两边扩展的长度
         *
         * @param str   字符串
         * @param left  左指针
         * @param right 右指针
         * @return 长度
         */
        private static int getExpandAroundCenterLength(String str, int left, int right) {
            // 找出该元素作为回文子串的起始位置还有结束位置
            while (left >= 0 && right < str.length() && str.charAt(left) == str.charAt(right)) {
                // 如果符合条件,左指针向左移动一格,右指针向右移动一格
                left--;
                right++;
            }
            // 得到长度
            return right - left - 1;
        }
    }
    

    Kotlin

    import kotlin.math.max
    
    /**
     * Created by TanJiaJun on 2021/6/14.
     * 5. 最长回文子串(Longest Palindromic Substring)
     * 难度:中等
     *
     * @see <a href="https://leetcode-cn.com/problems/longest-palindromic-substring/">Longest Palindromic Substring</a>
     */
    object LongestPalindromicSubstringKotlin {
    
        @JvmStatic
        fun main(args: Array<String>) {
            // 示例一
            print("示例一:")
    
            val firstStr = "babad"
            println(expandAroundCenterLongestPalindrome(firstStr))
    
            print("\n")
    
            // 示例二
            print("示例二:")
    
            val secondStr = "cbbd"
            println(expandAroundCenterLongestPalindrome(secondStr))
    
            print("\n")
    
            // 示例三
            print("示例三:")
    
            val thirdStr = "a"
            println(expandAroundCenterLongestPalindrome(thirdStr))
    
            print("\n")
    
            // 示例四
            print("示例四:")
    
            val fourthStr = "ac"
            println(expandAroundCenterLongestPalindrome(fourthStr))
        }
    
        /**
         * 方法一:枚举算法
         * 时间复杂度:O(N^3),其中N是字符串的长度
         * 空间复杂度:O(1)
         *
         * @param str 字符串
         * @return 结果
         */
        private fun longestPalindrome(str: String): String {
            var maxLength = 0
            var result = ""
            // 枚举所有的元素
            str.forEachIndexed { index, _ ->
                for (i in index + 1..str.length) {
                    val substring = str.substring(index, i)
                    if (isPalindromicSubstring(substring) && substring.length > maxLength) {
                        maxLength = substring.length
                        result = substring
                    }
                }
            }
            return result
        }
    
        /**
         * 判断字符串是否为回文串
         *
         * @param str 字符串
         * @return 结果
         */
        private fun isPalindromicSubstring(str: String): Boolean {
            val length = str.length
            for (i in 0 until length / 2) {
                // 找出该元素作为回文子串的起始位置还有结束位置
                if (str[i] != str[length - i - 1]) {
                    // 如果其中一个不相同,证明该字符串不是回文串
                    return false
                }
            }
            // 如果字符都相同,证明该字符串是回文串
            return true
        }
    
        /**
         * 方法二:中心扩展法(双指针)
         * 时间复杂度:O(N^2),其中N是字符串的长度
         * 空间复杂度:O(1)
         *
         * @param str 字符串
         * @return 结果
         */
        private fun expandAroundCenterLongestPalindrome(str: String): String {
            var start = 0
            var end = 0
            str.forEachIndexed { index, _ ->
                // 长度是奇数
                val oddLength = getExpandAroundCenterLength(str = str, left = index, right = index)
                // 长度是偶数
                val evenLength = getExpandAroundCenterLength(str = str, left = index, right = index + 1)
                // 得到最大长度
                val maxLength = max(oddLength, evenLength)
                if (maxLength > end - start) {
                    // 得到起始位置
                    start = index - (maxLength - 1) / 2
                    // 得到结束位置
                    end = index + maxLength / 2
                }
            }
            return str.substring(start, end + 1)
        }
    
        /**
         * 得到中心往两边扩展的长度
         *
         * @param str   字符串
         * @param left  左指针
         * @param right 右指针
         * @return 长度
         */
        private fun getExpandAroundCenterLength(str: String, left: Int, right: Int): Int {
            var l = left
            var r = right
            // 找出该元素作为回文子串的起始位置还有结束位置
            while ((l >= 0 && r < str.length && str[l] == str[r])) {
                // 如果符合条件,左指针向左移动一格,右指针向右移动一格
                l--
                r++
            }
            // 得到长度
            return r - l - 1
        }
    
    }
    

    题解

    枚举

    // LongestPalindromicSubstringKotlin.kt
    /**
     * 方法一:枚举
     * 时间复杂度:O(N^3),其中N是字符串的长度
     * 空间复杂度:O(1)
     *
     * @param str 字符串
     * @return 结果
     */
    private fun longestPalindrome(str: String): String {
        var maxLength = 0
        var result = ""
        // 枚举所有的元素
        str.forEachIndexed { index, _ ->
            for (i in index + 1..str.length) {
                val substring = str.substring(index, i)
                if (isPalindromicSubstring(substring) && substring.length > maxLength) {
                    maxLength = substring.length
                    result = substring
                }
            }
        }
        return result
    }
    
    /**
     * 判断字符串是否为回文串
     *
     * @param str 字符串
     * @return 结果
     */
    private fun isPalindromicSubstring(str: String): Boolean {
        val length = str.length
        for (i in 0 until length / 2) {
            // 找出该元素作为回文子串的起始位置还有结束位置
            if (str[i] != str[length - i - 1]) {
                // 如果其中一个不相同,证明该字符串不是回文串
                return false
            }
        }
        // 如果字符都相同,证明该字符串是回文串
        return true
    }
    

    时间复杂度:O(N^3),其中N是字符串的长度。

    空间复杂度:O(1)。

    暴力解法,枚举所有元素,要注意的是,由于回文串的特征是正读和反读都一样,例如:abba就是回文串abda就不是回文串了,所以我们只要找到某个字符,并且找到该字符对应索引的字符,只需要遍历该数组长度一半就可以判断该字符串是否为回文串,注释写得挺详细了,这里就不再赘述了。

    中心扩展法(双指针)

    // LongestPalindromicSubstringKotlin.kt
    /**
     * 方法二:中心扩展法(双指针)
     * 时间复杂度:O(N^2),其中N是字符串的长度
     * 空间复杂度:O(1)
     *
     * @param str 字符串
     * @return 结果
     */
    private fun expandAroundCenterLongestPalindrome(str: String): String {
        var start = 0
        var end = 0
        str.forEachIndexed { index, _ ->
            // 长度是奇数
            val oddLength = getExpandAroundCenterLength(str = str, left = index, right = index)
            // 长度是偶数
            val evenLength = getExpandAroundCenterLength(str = str, left = index, right = index + 1)
            // 得到最大长度
            val maxLength = max(oddLength, evenLength)
            if (maxLength > end - start) {
                // 得到起始位置
                start = index - (maxLength - 1) / 2
                // 得到结束位置
                end = index + maxLength / 2
            }
        }
        return str.substring(start, end + 1)
    }
    
    /**
     * 得到中心往两边扩展的长度
     *
     * @param str   字符串
     * @param left  左指针
     * @param right 右指针
     * @return 长度
     */
    private fun getExpandAroundCenterLength(str: String, left: Int, right: Int): Int {
        var l = left
        var r = right
        // 找出该元素作为回文子串的起始位置还有结束位置
        while ((l >= 0 && r < str.length && str[l] == str[r])) {
            // 如果符合条件,左指针向左移动一格,右指针向右移动一格
            l--
            r++
        }
        // 得到长度
        return r - l - 1
    }
    

    时间复杂度:O(N^2),其中N是字符串的长度。

    空间复杂度:O(1)。

    由于回文串的特征是正读和反读都一样,例如:abba就是回文串abda就不是回文串了,所以我们可以从该字符串的中间向两边扩展地遍历,这样就能快速地得到最长的回文子串,要注意的是,因为数组的长度可能是奇数,也可能是偶数,如果是奇数的话,中心点就只有一个;如果是偶数的话,中心点就有两个

    Z字形变换(ZigZag Conversion)

    难度:中等

    链接:ZigZag Conversion

    代码

    Java

    /**
     * Created by TanJiaJun on 2021/6/12.
     * 6. Z字形变换(ZigZag Conversion)
     * 难度:中等
     *
     * @see <a href="https://leetcode-cn.com/problems/zigzag-conversion/">ZigZag Conversion</a>
     */
    class ZigZagConversion {
    
        public static void main(String[] args) {
            // 示例一
            System.out.print("示例一:");
    
            String firstStr = "PAYPALISHIRING";
            int firstNumRows = 3;
            System.out.println(convert(firstStr, firstNumRows));
    
            System.out.print("\n");
    
            // 示例二
            System.out.print("示例二:");
    
            String secondStr = "PAYPALISHIRING";
            int secondNumRows = 4;
            System.out.println(convert(secondStr, secondNumRows));
    
            System.out.print("\n");
    
            // 示例三
            System.out.print("示例三:");
    
            String thirdStr = "A";
            int thirdNumRows = 1;
            System.out.println(convert(thirdStr, thirdNumRows));
        }
    
        /**
         * 时间复杂度:O(N),其中N是字符串的长度
         * 空间复杂度:O(N)
         *
         * @param str     字符串
         * @param numRows 行数
         * @return 结果
         */
        private static String convert(String str, int numRows) {
            if (numRows == 1) {
                // 如果只是一行的话,就直接返回该字符串
                return str;
            }
            // 创建长度是行数的StringBuilder数组,并且每个元素都创建StringBuilder对象
            StringBuilder[] stringBuilders = new StringBuilder[numRows];
            for (int i = 0; i < numRows; i++) {
                stringBuilders[i] = new StringBuilder();
            }
            // 索引
            int index = 0;
            // 行数
            int row = 0;
            int length = str.length();
            while (index < length) {
                // 从第一行开始,按照行数添加到对应的数组,并且追加字符,然后一直遍历到最后一行对应的数组
                while (index < length && row < numRows) {
                    char ch = str.charAt(index++);
                    stringBuilders[row++].append(ch);
                }
    
                // 此时row是最后一行,所以我们需要回到倒数第二行,执行以下逻辑
                row = numRows - 2;
    
                // 从倒数第二行开始,按照行数添加到对应的数组,并且追加字符,然后一直遍历到第一行的对应的数组
                while (index < length && row >= 0) {
                    char ch = str.charAt(index++);
                    stringBuilders[row--].append(ch);
                }
    
                // 此时row是-1,所以我们需要回到第二行,执行以下逻辑
                row += 2;
            }
            // 创建一个新的StringBuilder,将每一行对应的StringBuilder数组对应的StringBuilder追加到这个对象
            StringBuilder resultSB = new StringBuilder();
            for (StringBuilder stringBuilder : stringBuilders) {
                resultSB.append(stringBuilder);
            }
            // 将这个StringBuilder转成字符串
            return resultSB.toString();
        }
    
    }
    

    Kotlin

    /**
     * Created by TanJiaJun on 2021/6/14.
     * 6. Z字形变换(ZigZag Conversion)
     * 难度:中等
     *
     * @see <a href="https://leetcode-cn.com/problems/zigzag-conversion/">ZigZag Conversion</a>
     */
    object ZigZagConversionKotlin {
    
        @JvmStatic
        fun main(args: Array<String>) {
            // 示例一
            print("示例一:")
    
            val firstStr = "PAYPALISHIRING"
            val firstNumRows = 3
            println(convert(firstStr, firstNumRows))
    
            print("\n")
    
            // 示例二
            print("示例二:")
    
            val secondStr = "PAYPALISHIRING"
            val secondNumRows = 4
            println(convert(secondStr, secondNumRows))
    
            print("\n")
    
            // 示例三
            print("示例三:")
    
            val thirdStr = "A"
            val thirdNumRows = 1
            println(convert(thirdStr, thirdNumRows))
        }
    
        /**
         * 时间复杂度:O(N),其中N是字符串的长度
         * 空间复杂度:O(N)
         *
         * @param str     字符串
         * @param numRows 行数
         * @return 结果
         */
        private fun convert(str: String, numRows: Int): String {
            if (numRows == 1) {
                // 如果只是一行的话,就直接返回该字符串
                return str
            }
            // 创建长度是行数的StringBuilder数组,并且每个元素都创建StringBuilder对象
            val stringBuilders = Array(numRows, init = { StringBuilder() })
            // 索引
            var index = 0
            // 行数
            var row = 0
            val length = str.length
            while (index < length) {
                // 从第一行开始,按照行数添加到对应的数组,并且追加字符,然后一直遍历到最后一行对应的数组
                while (index < length && row < numRows) {
                    stringBuilders[row++].append(str[index++])
                }
    
                // 此时row是最后一行,所以我们需要回到倒数第二行,执行以下逻辑
                row = numRows - 2
    
                // 从倒数第二行开始,按照行数添加到对应的数组,并且追加字符,然后一直遍历到第一行的对应的数组
                while (index < length && row >= 0) {
                    stringBuilders[row--].append(str[index++])
                }
    
                // 此时row是-1,所以我们需要回到第二行,执行以下逻辑
                row += 2
            }
            // 创建一个新的StringBuilder,将每一行对应的StringBuilder数组对应的StringBuilder追加到这个对象
            val resultSB = StringBuilder()
            stringBuilders.forEach { resultSB.append(it) }
            // 将这个StringBuilder转成字符串
            return resultSB.toString()
        }
    
    }
    

    时间复杂度:O(N),其中N是字符串的长度。

    空间复杂度:O(N)。

    题解

    根据题目我们可以知道,字符串是按着反向N字形排列的,我们可以先创建一个长度是行数StringBuilder数组,然后定义一个row这样的指针来确定行数,为了方便理解,我举个例子,假设字符串PAYPALISHIRING,行数是3,我们从第一行开始,按照行数将字符添加到对应的数组,并且追加字符,然后一直遍历到最后一行对应的数组,此时这三个数组的情况如下所示:

    • 第一个数组:P
    • 第二个数组:A
    • 第三个数组:Y

    此时的row的值是4,然后这个时候根据题目要求,我们的指针要回到倒数第二行,所以我们就要将row的值调整为行数减去2,也就是3-2等于1,然后开始继续遍历,此时这三个数组的情况如下所示:

    • 第一个数组:P
    • 第二个数组:A、P
    • 第三个数组:Y

    然后我们的指针要从倒数第二行开始,按照行数添加到对应的数组,并且追加字符,然后一直遍历到第一行的对应的数组,此时这三个数组的情况如下所示:

    • 第一个数组:P、A
    • 第二个数组:A、P、L
    • 第三个数组:Y、I

    此时row的值是-1,最后根据题目要求,我们的指针row要回到第二行,所以我们就要将row的值调整为自增2,也就是-1+2等于1,然后开始继续遍历,此时这三个数组的情况如下所示:

    • 第一个数组:P、A
    • 第二个数组:A、P、L、S
    • 第三个数组:Y、I

    以此类推遍历下去,后面的逻辑就跟前面的逻辑一样了,这里就不再赘述了。

    最后将这个StringBuilder数组遍历后追加到一个新的StringBuilder对象,然后转成字符串就可以得到最后的结果了。

    我的GitHub:TanJiaJunBeyond

    Android通用框架:Android通用框架

    我的掘金:谭嘉俊

    我的简书:谭嘉俊

    我的CSDN:谭嘉俊

    相关文章

      网友评论

          本文标题:阿俊带你用Kotlin刷算法(二)

          本文链接:https://www.haomeiwen.com/subject/pcwdyltx.html