LeetCode 简单难度_第一周总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_21586317/article/details/81592499

1.两数之和

给定一个整数数组和一个目标值,找出数组中和为目标值的两个数
你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用

示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

解决方案


方法一:暴力法

private static int[] twoSum(int[] nums, int target) {
    if(nums == null || nums.length == 1) {
        return new int[]{0, 0};
    }
    for (int i = 0; i < nums.length - 1; i++) {
        for (int j = i + 1; j < nums.length; j++) {
            if (target == nums[i] + nums[j]) {
                return new int[] {i, j};
            }
        }
    }
    throw new IllegalArgumentException("No two sum solution");
}

复杂度分析
时间复杂度:O(n^2)
空间复杂度:O(1)

方法二:哈希表
把数组中的元素作为 key 插入到 hashmap 中,值存元素下标

private static int[] twoSum(int[] nums, int target) {
    if (nums == null || nums.length == 1) {
        return new int[]{0, 0};
    }
    Map<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        int complement = target - nums[i];
        if (map.containsKey(complement)) {
            return new int[] {map.get(complement), i};
        }
        map.put(nums[i], i);
    }
    throw new IllegalArgumentException("No two sum solution");
}

复杂度分析:
时间复杂度:O(n)
空间复杂度:O(n)


7.反转整数

给定一个 32 位有符号整数,将整数中的数字进行反转

示例 1:
输入: 123
输出: 321

示例 2:
输入: -123
输出: -321

示例 3:
输入: 120
输出: 21

注意:假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]。根据这个假设,如果反转后的整数溢出,则返回 0

方法:每次取一个数进行保存,保存之前判断是否有可能会溢出
溢出有四种情况:
a. 上次保存的数 > Integer.MAX_VALUE / 10,则肯定溢出
b. 上次保存的数 == Integer.MAX_VALUE / 10,且当前即将要保存的数大于 7,则会溢出
c. 上次保存的数 < Integer.MIN_VALUE / 10,则肯定溢出
d. 上次保存的数 == Integer.MIN_VALUE / 10,且当前即将要保存的数小于 -8,则会溢出

private static int reverse(int x) {
    int rev = 0;
    while (x != 0) {
        int pop = x % 10;
        x /= 10;
        if (rev > Integer.MAX_VALUE / 10 || (rev == Integer.MAX_VALUE / 10 && pop > 7)) return 0;
        if (rev < Integer.MIN_VALUE / 10 || (rev == Integer.MIN_VALUE / 10 && pop < -8)) return 0;
        rev = rev * 10 + pop;
    }
    return rev;
}

复杂度分析
时间复杂度:O(log(n))
空间复杂度:O(1)


9.回文数

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数

示例 1:
输入: 121
输出: true

示例 2:
输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数

示例 3:
输入: 10
输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数

进阶:
你能不将整数转为字符串来解决这个问题吗?

方法:反转后半部分,再和前半部分比较,相等则为回文数
怎么确定一半?
将原始数字除以 10,然后给反转后的数字乘上 10,所以,当原始数字小于反转后的数字时,就意味着我们已经处理了一半位数的数字

private static boolean isPalindrome(int x) {
    if (x <0 || (x % 10 == 0 && x != 0)) {
        return false;
    }
    int revertedNumber = 0;
    while (x > revertedNumber) {
        revertedNumber = revertedNumber * 10 + x % 10;
        x /= 10;
    }
    return x == revertedNumber || x == revertedNumber / 10;
}

复杂度分析
时间复杂度:参考给的是 O(log(n))
空间复杂度:O(1)


13.罗马数字转整数

罗马数字包含以下七种字符:I, V, X, L,C,D 和 M

字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内

自己写的

private static int romanToInt(String s) {
    // 输入的字符串为 null 或长度为 0
    if (s == null || s.length() == 0) {
        return 0;
    }
    String roman = "IVXLCDM";
    char[] cs = s.toCharArray();
    // 遍历输入的字符串
    for (int i = 0; i < cs.length; i++) {
        // 当前字符不在罗马数字对应的字符范围内
        if (!roman.contains(cs[i] + "")) {
            return 0;
        }
    }
    // 若连续输入 4 个罗马字符,抛异常,提示罗马数字一般最多为连续三个字符
    if (s.contains("IIII") || s.contains("VVVV") || s.contains("XXXX") || s.contains("LLLL") || s.contains("CCCC")
            || s.contains("DDDD") || s.contains("MMMM")) {
        throw new IllegalArgumentException("连续字母不能超过三个");
    }

    Map<Character, Integer> map = new HashMap<>();
    map.put('I', 1);
    map.put('V', 5);
    map.put('X', 10);
    map.put('L', 50);
    map.put('C', 100);
    map.put('D', 500);
    map.put('M', 1000);
    int len = s.length();
    // 初始化 sum 的值,赋值默认取最后一个罗马字符的值
    int sum = map.get(s.charAt(len - 1));
    for (int i = 0; i < len - 1; i++) {
        if (map.get(s.charAt(i)) < map.get(s.charAt(i + 1))) {
            sum -= map.get(s.charAt(i));
        } else {
            sum += map.get(s.charAt(i));
        }
    }
    return sum;
}

复杂度分析
时间复杂度:O(n)
空间复杂度:O(n)


14.最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀
如果不存在公共前缀,返回空字符串 “”

示例 1:
输入: [“flower”,”flow”,”flight”]
输出: “fl”

示例 2:
输入: [“dog”,”racecar”,”car”]
输出: “”

说明:
所有输入只包含小写字母 a-z

自己写的

private static String longestCommonPrefix(String[] strs) {
    // 输入的数组为 null,或者数组所含元素个数为 0,即 strs = new String[]{}
    if (strs == null) {
        // 直接返回空字符串
        return "";
    } else if (strs.length == 1) {// 输入的数组所含元素个数为 1
        // 直接返回该字符串
        return strs[0];
    }
    // 获取输入的数组所含元素个数
    int len = strs.length;
    // 初始化数组元素最短长度为输入的数组中第一个元素的长度
    int lessStrLen = strs[0].length();
    // 数组第一个元素长度为 0
    if (lessStrLen == 0) {
        // 直接返回空字符串
        return "";
    }
    // 从数组下标为 1 处遍历数组
    for (int i = 1; i < len; i++) {
        // 获取当前位置元素的长度
        int currStrLen = strs[i].length();
        // 元素长度为 0
        if (currStrLen == 0) {
            // 返回空字符串
            return "";
        }
        // 如果当前元素长度小于记录的最小元素长度
        if (currStrLen < lessStrLen) {
            // 更新最小元素长度为当前元素长度
            lessStrLen = currStrLen;
        }
    }
    // 创建 map 对象
    Map<Character, Integer> map = new HashMap<>(lessStrLen);
    // 当前遍历的次数
    int index = 0;
    // 每轮遍历的个数
    int count = 0;
    // 当前遍历的字符
    char c1 = 0;
    // 轮数,即最短元素长度
    for (int i = 0; i < lessStrLen; i++) {
        // 当前遍历的次数
        index = i + 1;
        // 开始新的一轮,已遍历的个数清零
        count = 0;
        // 每一轮的次数,即数组长度
        for (int j = 0; j < len; j++) {
            // 每次获取数组第 j 个元素的第 i 个字符
            c1 = strs[j].charAt(i);
            // 从第二个元素开始,map 中若不存在 c1,表示数组下标为 j 的元素,第 i 个字符在 map 中不存在
            if (j != 0 && map.get(c1) == null) {
                // 返回第 i 个字符之前的字符串
                return strs[0].substring(0, i);
            }
            // 当前第 i 轮遍历的个数加一
            count += 1;
            // 把 c1 放到数组中,值随意,判断的时候关键是判断 c1 这个 key 对应的 value 是否存在
            map.put(c1, j + 1);
        }
        // 当前第 i 轮遍历结束,把 c1 置空,方便下一轮对字符进行存储、判断
        map.put(c1, null);
    }
    // 最后一轮遍历的个数不等于数组元素的个数,即表示最后一轮没有遍历完就出现了不同的字符
    if (count != len) {
        // 最后一轮之前的轮数对应的字符串都是相同的,相同的轮数为当前遍历的次数 index - 1
        index--;
    }
    // 返回 index 之前的字符串
    return strs[0].substring(0, index);
}

复杂度分析
时间复杂度:O(n^2)
空间复杂度:O(n)


20.有效的括号

给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

示例 1:
输入: “()”
输出: true

示例 2:
输入: “()[]{}”
输出: true

示例 3:
输入: “(]”
输出: false

示例 4:
输入: “([)]”
输出: false

示例 5:
输入: “{[]}”
输出: true

自己写的

private static boolean isValid(String s) {
    if (s == null) {
        return false;
    }
    if (s.length() == 0) {
        return true;
    }
    boolean flag = false;

    String[] strs = { "()", "{}", "[]" };
    while (s.length() != 0) {
        flag = false;
        for (int i = 0; i < strs.length; i++) {
            // 当前字符串包含有效括号
            if (s.contains(strs[i])) {
                flag = true;
                // 剔除当前字符串中的有效括号
                s = s.replace(strs[i], "");
                // 跳出循环
                break;
            }
            // 此时为遍历有效括号数组 strs 最后一个元素,即有效括号数组在遍历完之前还没有跳出循环
            // 则证明当前字符串中含有非有效括号
            if (i == strs.length - 1) {
                // 返回 falg,此时 flag 为 false
                return flag;
            }
        }
    }
    // 全部为有效括号,此时 flag 为 true
    return flag;
}

复杂度分析
时间复杂度:
a. 最好情况,返回 true,即每次都找到有效括号,O(log2(n))
b. 最差情况,返回 false,数组遍历完也没找到有效括号,O(n)
空间复杂度:O(1)

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页