End

Kotlin 朱涛 实战 刷题 LeetCode

本文地址


目录

春节刷题计划 | Kotlin + LeetCode

移除字符

移除字符串中的所有元音字母 a、e、i、o、u。

public String removeVowels(String s) {
    return s.replaceAll("[aeiou]", "");
}
val String.removeVowels: String get() = replace("[aeiou]".toRegex(), "")
val String.removeVowels2: String get() = filter { it !in setOf('a', 'e', 'i', 'o', 'u') }

冒泡排序

public static int[] bubbleSort(int[] array) {
    int size = array.length;
    for (int i = 0; i < size; ++i) {
        for (int j = 0; j < size - i - 1; ++j) {
            if (array[j] > array[j + 1]) {
                int tmp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = tmp;
            }
        }
    }
    return array;
}
fun sort(array: IntArray): IntArray {
    for (i in array.indices) {
        for (j in 0 until array.size - i - 1) {
            if (array[j] > array[j + 1]) {
                val tem = array[j]
                array[j] = array[j + 1]
                array[j + 1] = tem
            }
        }
    }
    return array
}

最常见的单词

LeetCode-819:给定一个段落 (paragraph) 和一个禁用单词列表 (banned)。返回出现次数最多,同时不在禁用列表中的单词。

题目保证至少有一个词不在禁用列表中,而且答案唯一。禁用列表中的单词用小写字母表示,不含标点符号。段落中的单词不区分大小写。答案都是小写字母。

Java

public static String mostCommonWord(String paragraph, String[] banned) {
    HashMap<String, Integer> map = new HashMap<>();
    String[] strings = paragraph.toLowerCase().replaceAll("[^A-Za-z]", " ").split(" ");
    for (String s : banned) {
        map.put(s, Integer.MIN_VALUE);
    }
    map.put("", Integer.MIN_VALUE);
    for (String s : strings) {
        Integer count = map.get(s);
        map.put(s, count == null ? 1 : count + 1);
    }

    String text = null;
    int max = 0;
    for (String next : map.keySet()) {
        Integer count = map.get(next);
        if (count != null && count > max) {
            text = next;
            max = count;
        }
    }
    return text;
}

Kotlin

fun mostCommonWord(paragraph: String, banned: Array<String>): String = paragraph
    .lowercase(Locale.getDefault()) // Returns a copy of this string converted to lower case 
    .replace(Regex("[^A-Za-z]"), " ")
    .split(" ")
    .asSequence() // Call chain on a collection could be converted into 'Sequence' to improve performance
    .filter { it !in banned }
    .groupBy { it } // Groups elements of the original sequence
    .map { Pair(it.key, it.value.size) } // 转换为 List
    .maxBy { it.second } // Returns the first element yielding the largest value of the given function
    .first

比较版本号

LeetCode-165:比较版本号

  • 版本号仅包含数字和 .
  • 1.0 小于 1.1
  • 2.0 大于 1.5.6
  • 1.1 等于 1.001 等于 1.1.0

Java

public class Test {
    public static void main(String[] args)
    {
        System.out.println(compareVersion("3.10.0101.0", "3.10.0102."));
    }

    public static int compareVersion(String version1, String version2)
    {
        int[] v1 = getVersions (version1);
        int[] v2 = getVersions (version2);
        boolean isV1LengthLong = v1 . length > v2 . length;
        int minLength = isV1LengthLong ? v2 . length : v1 . length;
        for (int i = 0; i < minLength; i++) {
        if (v1[i] != v2[i]) {
            return v1[i] > v2[i] ? 1 :-1;
        }
    }

        int maxLength = isV1LengthLong ? v1 . length : v2 . length;
        int[] maxLengthVersion = isV1LengthLong ? v1 : v2;
        for (int i = minLength; i < maxLength; i++) {
        if (maxLengthVersion[i] != 0) {
            return isV1LengthLong ? 1 :-1;
        }
    }

        return 0;
    }

    private static int[] getVersions(String version)
    {
        String[] strings = version . split ("\\.");
        int[] versions = new int[strings.length];
        for (int i = 0; i < strings.length; i++) {
        String newString = strings [i];
        while (newString.length() > 1 && newString.startsWith("0")) {
            newString = newString.substring(1);
        }
        versions[i] = Integer.parseInt(newString);
    }

        return versions;
    }
}

Kotlin - 1

fun compareVersion(version1: String, version2: String): Int {
    val list1 = version1.split(".")
    val list2 = version2.split(".")

    var i = 0
    while (i < list1.size || i < list2.size) {    // 只要有一个没遍历完,就要继续遍历
        val v1 = list1.getOrNull(i)?.toInt() ?: 0 // 类型转换,当数组越界时,转换为 0
        val v2 = list2.getOrNull(i)?.toInt() ?: 0
        if (v1 != v2) {
            return v1.compareTo(v2) // Int.compareTo() 的返回值,刚好符合题目的要求
        }
        i++
    }
    return 0
}

核心代码:

val v1 = list1.getOrNull(i)?.toInt() ?: 0

// 等价于以下三步
val versionStr: String? = list1.getOrNull(i) // 当数组越界时,返回 null
val versionInt: Int? = versionStr?.toInt()   // 当变量不为空时,才调用
val v1: Int = versionInt ?: 0                // 当变量为空时,才赋值

Kotlin - 2

前面的思路,我们是使用的 Kotlin 的库函数 split() 进行分割,然后对列表进行遍历来判断的版本号。其实,我们可以自己遍历字符串,来模拟 split 的过程,并在遍历时把比对的工作也一起做完。

fun compareVersion(version1: String, version2: String): Int {
    val v1 = Version(0, 0, version1)
    val v2 = Version(0, 0, version2)

    while (v1.index < version1.length || v2.index < version2.length) {
        v1.dealSubVersionValue()
        v2.dealSubVersionValue()
        if (v1.subValue != v2.subValue) {
            return v1.subValue.compareTo(v2.subValue)
        }
    }
    return 0
}

data class Version(var index: Int, var subValue: Int, val versionStr: String) {
    val baseValue = '0'.toInt()
    fun dealSubVersionValue() {
        subValue = 0
        while (index < versionStr.length && versionStr[index] != '.') {
            subValue = subValue * 10 + versionStr[index].toInt() - baseValue
            index++
        }
        index++
    }
}

求解一元一次方程

LeetCode-640:输入一个方程,以 x=value 的形式返回该方程的解

  • 方程仅包含 +-= 符号、变量 x 和其对应系数
  • 如果方程没有解,请返回 No solution
  • 如果方程有无限解,请返回 Infinite solutions
  • 如果方程中只有一个解,要保证返回值是一个整数
输入: "x+5-3+x=6+x-2"
输出: "x=2"

输入: "x=x"
输出: "Infinite solutions"

输入: "x=x+1"
输出: "No solution"

Java

public static String solveEquation(String equation) { // x+5-3+2x=6+x-2
    int xCount = 0;   // 移到左边的 x 系数之和
    int addValue = 0; // 移到右边的数字之和
    int equalIndex = equation.indexOf('='); // 等号的位置

    for (int i = 0; i < equation.length(); i++) {
        int fromIndex = i;
        if (i == 0) {
            i++;
        }
        for (int j = i; j < equation.length(); j++) {
            char c = equation.charAt(j);
            if (c == '+' || c == '-' || c == '=') {
                break;
            }
            i++;
        }

        String subString = equation.substring(fromIndex == 0 ? fromIndex : fromIndex - 1, i);
        subString = subString.startsWith("=") ? subString.substring(1) : subString;
        // System.out.println("值为:" + subString);
        if (subString.endsWith("x")) {
            subString = subString.substring(0, subString.length() - 1);
            int tempCount;
            if (subString.length() == 0) { // x
                tempCount = 1;
            } else {
                if (subString.length() == 1 && (subString.startsWith("+") || subString.startsWith("-"))) { // +x 或 -x
                    tempCount = subString.charAt(0) == '+' ? 1 : -1;
                } else { // +5x 或 5x 或 53x 或 -2x
                    tempCount = Integer.parseInt(subString);
                }
            }
            xCount = i > equalIndex ? xCount - tempCount : xCount + tempCount; // 左正右负
        } else if (subString.length() > 0) { // 过滤掉 = 产生的一个空字符串
            int tempValue = Integer.parseInt(subString);
            addValue = i > equalIndex ? addValue + tempValue : addValue - tempValue; // 左负右正
        }

        // System.out.println("结果:" + xCount + "x = " + addValue);
        if (xCount == 0) {
            return addValue == 0 ? "Infinite solutions" : "No solution";
        } else {
            return "x=" + (addValue / xCount);
        }
    }

Kotlin

fun solveEquation(equation: String): String { // x+5-3+2x=6+x-2
    var xCount = 0   // 移到左边的 x 系数之和
    var addValue = 0 // 移到右边的数字之和
    val equalIndex = equation.indexOf('=') // 等号的位置
    var i = 0
    while (i < equation.length) {
        val fromIndex = i
        if (i == 0) {
            i++
        }
        for (j in i until equation.length) {
            val c: Char = equation[j]
            if (c == '+' || c == '-' || c == '=') {
                break
            }
            i++
        }
        var subString = equation.substring(if (fromIndex == 0) fromIndex else fromIndex - 1, i)
        subString = if (subString.startsWith("=")) subString.substring(1) else subString
        println("值为:$subString")
        if (subString.endsWith("x")) {
            subString = subString.substring(0, subString.length - 1)
            val tempCount = if (subString.isEmpty()) 1 // x
            else {
                if (subString.length == 1 && (subString.startsWith("+") || subString.startsWith("-"))) { // +x 或 -x
                    if (subString[0] == '+') 1 else -1
                } else subString.toInt() // +5x 或 5x 或 53x 或 -2x
            }
            xCount = if (i > equalIndex) xCount - tempCount else xCount + tempCount // 左正右负
        } else if (subString.isNotEmpty()) { // 过滤掉 = 产生的一个空字符串
            val tempValue = subString.toInt()
            addValue = if (i > equalIndex) addValue + tempValue else addValue - tempValue // 左负右正
        }
        i++
    }
    println("结果:${xCount}x = $addValue")
    return if (xCount == 0) if (addValue == 0) "Infinite solutions" else "No solution"
    else "x=" + addValue / xCount
}

分数加减运算

本文地址

题目描述

LeetCode-640

给定一个表示分数加减运算的字符串,返回计算结果。

  • 输入、输出字符串只包含 0-9 的数字,以及 /+- 符号(不会有空格)
  • 输入、输出分数格式均为 (-)分子/分母,正数前面的 + 会被省略
  • 输入只包含合法的最简分数,分子、分母的范围是[1,10](整数也会用分数来表示)
  • 输入分数的个数不超过 10 个,最终结果的分子与分母不超过 32 位整数(不会溢出)
  • 输出的分数需要是最简分数形式(整数也需要用分数来表示)

题目分析

主要步骤:

  • 分割、解析分数
  • 计算分母的最小公倍数
  • 将分数进行通分
  • 计算分子加减运算的结果
  • 将计算结果约分

求最小公倍数 & 最大公约数

最大公约数计算公式如下

20 36 -- 16
16 20 -- 4
4  16 -- 0  --> 最大公约数是 4

3 8 -- 5
3 5 -- 2
2 3 -- 1
1 2 -- 0    --> 最大公约数是 1

22 36 -- 14
14 22 -- 8
8  14 -- 6
6  8  -- 2
2  6  -- 0  --> 最大公约数是 2

最小公倍数 = a * b /最大公约数

// 求两个数的最大公约数,Greatest Common Divisor
private fun gcd(a: Int, b: Int): Int {
    var (big, small) = if (a > b) a to b else b to a

    while (small != 0) {
        val temp = small
        small = big % small
        big = temp
    }
    return big
}

// 求两个数的最小公倍数,Least Common Multiple
private fun lcm(a: Int, b: Int) = a * b / gcd(a, b)

完整代码

fun fractionAddition(expression: String): String {
    val pairs = expression
        .replace("-", "+-")
        .split("+")                          // 拆分每个分数
        .filter { it.isNotBlank() }          // 过滤非法数据
        .map { it.split("/") }               // 拆分分子分母
        .map { Pair(it[0].toInt(), it[1].toInt()) }

    val lcm = pairs
        .map { it.second }                   // 分母的集合
        .reduce { acc, i -> lcm(acc, i) }    // 所有分母的最小公倍数

    val sum = pairs
        .map { it.first * lcm / it.second }  // 分子通分
        .reduce { acc, i -> acc + i }        // 所有分子相加

    val gcd = gcd(kotlin.math.abs(sum), lcm) // 分子和分母的最大公约数
    val result = "${sum / gcd}/${lcm / gcd}" // 简化分数
    
    println("lcm: $lcm, sum: $sum, gcd: $gcd, result: $result")
    return result
}

private val List<Int>.lcm: Int get() = reduce { acc, i -> lcm(acc, i) }

// 求两个数的最大公约数,Greatest Common Divisor
private fun gcd(a: Int, b: Int): Int {
    var (big, small) = if (a > b) a to b else b to a

    while (small != 0) {
        val temp = small
        small = big % small
        big = temp
    }
    return big
}

// 求两个数的最小公倍数,Least Common Multiple
private fun lcm(a: Int, b: Int) = a * b / gcd(a, b)

2017-10-20

posted @ 2017-10-20 11:36  白乾涛  阅读(3607)  评论(0编辑  收藏  举报