美国求职-刷题day2

第二天

Leetcode 9. Palindrome Number

Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.

Example 1: Input: 121 Output: true
Example 2:Input: -121 Output: false Explanation: From left to right, it reads-121. From right to left, it becomes 121-. Therefore it is not a palindrome.
Example 3:Input: 10 Output: false Explanation: Reads 01 from right to left.
Therefore it is not a palindrome.
Follow up:Coud you solve it without converting the integer to a string?

判断一个数字是否为回文数,且最好不要使用字符串反转,这道题和day1的7非常相似,信手捏来

 public boolean isPalindrome(int x) {
        if (x < 0) {
            return false;
        }
        int origin = x;
        int result = 0;
        while (x != 0) {
            result = result * 10 + x % 10;
            x = x / 10;
        }
        return result == origin;
    }

注意加好边界即可,官方的题解是只需比较前一半的数字即可,把 while (x != 0) 优化为while(x > result)然后比较x与result即可,但这个边界条件考虑的太多,我个人认为不如我们的朴素解法更好

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

Leetcode 13. Roman to Integer

Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.
Symbol Value
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
For example,
two is written as II in Roman numeral, just two one’s added together.Twelve is written as, XII, which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II.
Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:

I can be placed before V (5) and X (10) to make 4 and 9.
X can be placed before L (50) and C (100) to make 40 and 90.
C can be placed before D (500) and M (1000) to make 400 and 900.
Given a roman numeral, convert it to an integer. Input is guaranteed to be within
the range from 1 to 3999.
Example 1: Input: “III” Output: 3
Example 2: Input: “IV” Output: 4
Example 3:Input: “IX” Output: 9
Example 4:Input: “LVIII” Output: 58 Explanation: L = 50, V= 5, III = 3.
Example 5:Input: “MCMXCIV” Output: 1994 Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.

这道题是要开发一个罗马数字和阿拉伯数字的换算工具,题干提示我们应该从大到小左往右转换罗马数字

   public int romanToInt(String s) {
        int result = 0;
        char[] romans = s.toCharArray();
        for (int i = 0; i < romans.length; i++) {

            if (romans[i] == 'M') {
                if (i > 0 && romans[i - 1] == 'C') {
                    result -= 200;
                }
                result += 1000;
            } else if (romans[i] == 'D') {
                if (i > 0 && romans[i - 1] == 'C') {
                    result -= 200;
                }
                result += 500;

            } else if (romans[i] == 'C') {
                if (i > 0 && romans[i - 1] == 'X') {
                    result -= 20;
                }
                result += 100;

            } else if (romans[i] == 'L') {
                if (i > 0 && romans[i - 1] == 'X') {
                    result -= 20;
                }
                result += 50;

            } else if (romans[i] == 'X') {
                if (i > 0 && romans[i - 1] == 'I') {
                    result -= 2;
                }
                result += 10;
            } else if (romans[i] == 'V') {
                if (i > 0 && romans[i - 1] == 'I') {
                    result -= 2;
                }
                result += 5;

            } else if (romans[i] == 'I') {
                result += 1;
            }
        }
        return result;
    }

纯逻辑流,比较偷懒的方式是构建一个hash 表,把所有的组合情况的都放进去,然后逐一遍历两个字母的组合是否存在于hash表里,有则直接加上对应数字,没有则加上1个字母对应的数字。

 public int romanToIntByHash(String s) {
        Map<String, Integer> map = new HashMap<>();
        map.put("I", 1);
        map.put("IV", 4);
        map.put("V", 5);
        map.put("IX", 9);
        map.put("X", 10);
        map.put("XL", 40);
        map.put("L", 50);
        map.put("XC", 90);
        map.put("C", 100);
        map.put("CD", 400);
        map.put("D", 500);
        map.put("CM", 900);
        map.put("M", 1000);

        int result = 0;
        for (int i = 0; i < s.length(); i++) {
            if (i + 2 <= s.length() && map.containsKey(s.substring(i, i + 2))) {
                result += map.get(s.substring(i, i + 2));
                i++;
            } else {
                result += map.get(s.substring(i, i + 1));
            }
        }
        return result;
    }

二者时间复杂度相同,执行结果相差如下,个人更喜欢第一种(4ms)
在这里插入图片描述

Leetcode 14. Longest Common Prefix

Write a function to find the longest common prefix string amongst an array of strings.
If there is no common prefix, return an empty string “”.
Example 1: Input: [“flower”,“flow”,“flight”] Output: “fl”
Example 2: Input: [“dog”,“racecar”,“car”] Output: “” Explanation: There is no
common prefix among the input strings. Note:
All given inputs are in lowercase letters a-z.

找出相同字符串,代码如下

//找出最大相同字符串
 public String longestCommonString(String[] strs) {
        if (strs == null || strs.length == 0) {
            return "";
        }
        if (strs.length == 1) {
            return strs[0];
        }
        String target = strs[0];
        String subString, ans = "";
        int autoLength;

        for (int i = 0; i < target.length(); i++) {
            autoLength = 1;
            while (i + autoLength <= target.length()) {
                subString = target.substring(i, i + autoLength);
                for (int j = 1; j < strs.length; j++) {
                    if (!strs[j].contains(subString)) {
                        break;
                    } else if (j == strs.length - 1) {
                        if (subString.length() > ans.length()) {
                            ans = subString;
                        }
                    }
                }
                if (!ans.equals(subString)) {
                    break;
                } else {
                    autoLength++;
                }
            }
        }
        return ans;
    }

做完以后提交发现测试用例不通过,一细看才发现题目是要求找出公共前缀,prefix!所以我们的算法中做了没必要的逐字对比,所以删减后如下

//找出最大前缀数
    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) {
            return "";
        }
        if (strs.length == 1) {
            return strs[0];
        }
        String target = strs[0];
        String subString, ans = "";
        int autoLength;

        autoLength = 1;
        while (autoLength <= target.length()) {
            subString = target.substring(0, autoLength);
            for (int j = 1; j < strs.length; j++) {
                if (!strs[j].startsWith(subString)) {
                    break;
                } else if (j == strs.length - 1) {
                    if (subString.length() > ans.length()) {
                        ans = subString;
                    }
                }
            }
            if (!ans.equals(subString)) {
                break;
            } else {
                autoLength++;
            }
        }
        return ans;
    }

执行用时 :2 ms, 在所有 Java 提交中击败了38.72%的用户

我们的暴力解法性能果然很差,时间复杂度为o(n*m),m为首个字串的长度,官方题解提供了几个角度来思考这个问题:
1、水平扫描法
前两个字串取出最大前缀,再跟第三个取出最大前缀,以此类推,如果是空串则跳出循环,否则在多次循环后最终返回结果

    public String longestCommonPrefix1(String[] strs) {
        if (strs.length == 0) {
            return "";
        }
        String prefix = strs[0];
        for (int i = 1; i < strs.length; i++) {
            while (strs[i].indexOf(prefix) != 0) {
                prefix = prefix.substring(0, prefix.length() - 1);
                if (prefix.isEmpty()) return "";
            }
        }
        return prefix;
    }

2、纵向扫描
如果最后一个字符串最短,该怎么在上面的情况上做优化呢?我们可以每次把每个字符串的每一列进行比较,这样在刚刚提到的情况下,这种算法的时间复杂度要优于第一种方法

public String longestCommonPrefix2(String[] strs) {
        if (strs.length == 0) {
            return "";
        }
        for (int i = 0; i < strs[0].length(); i++) {
            char t = strs[0].charAt(i);
            for (int j = 0; j < strs.length; j++) {
                if (i == strs[j].length() || strs[j].charAt(i) != t) {
                    return strs[0].substring(0, i);
                }
            }
        }
        return strs[0];
    }

3、分治(Divide and conquer)
4、二分查找法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值