杂记LeetCode刷题

1. 两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

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

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int length = nums.length;
        for(int i = 0; i < length; i++){
            for(int j = i + 1; j < length; j++){
                if(target == (nums[i] + nums[j])){
                    return new int[]{i,j};
                }
            }
        }
        return null;
    }
}
执行用时	内存消耗
38 ms	40.6 MB	

官方答案:
使用HashMap,将数据逐个加入,每次加入时计算该数对应的解然后判断是否map中是否存在,若存在则返回对应的key和该数的值

class Solution {
    public int[] twoSum(int[] nums, int target) {
        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");
    }
}

2.两数之和

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头

示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

我的答案:参照了官方答案
对所有ListNode使用一个变量替代,初始化一个表示取模结果的变量carry
当ab任一不为空时获取ab的val,并将取余后的结果加入结果的下一个节点,将取模的结果存入carry下次循环使用,然后让ab指向下一个节点,循环结束后若carry大于0则将值赋给下一个节点

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
       ListNode a = l1;
       ListNode b = l2;
       ListNode c = new ListNode(0);
       ListNode d = c;
       int carry = 0;
       while(a != null || b != null){
        int l11 = (a != null)? a.val:0;
        int l22 = (b != null)? b.val:0;
        int sum = carry+l11+l22;
        carry=sum/10;
        d.next=new ListNode(sum%10);
        d=d.next;
        if(a!=null){
            a = a.next;
        }
        if(b != null){
            b = b.next;
        }
       }
       if(carry>0){
           d.next = new ListNode(carry);
       }
       return c.next;
    }
}

3. 无重复字符的最长字串

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

解法:转自力扣用户LeetCode的答案
暴力破解:遍历数组,对每一个字符进行查重,查重方式是取当前字符为基本字符,然后检测字符串中是否有重复字符,若没有则再取当前字符和后一位字符重复上述步骤

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        int ans = 0;
        for (int i = 0; i < n; i++)		// 遍历每个字符
            for (int j = i + 1; j <= n; j++)		// 将当前字符和后几位字符查重校验
                if (allUnique(s, i, j)) ans = Math.max(ans, j - i);
        return ans;
    }

    public boolean allUnique(String s, int start, int end) {
        Set<Character> set = new HashSet<>();
        for (int i = start; i < end; i++) {
            Character ch = s.charAt(i);
            if (set.contains(ch)) return false;
            set.add(ch);
        }
        return true;
    }
}

滑动窗口:
如图所示,我们称索引 i ~ j 之间的区间为窗口,当当前字符在集合set中不存在时将该字符加如集合set并将索引 j + 1 ,当当前字符在集合set中存在时删除集合set中的该字符(字符串第 i 位)并将i+1
最好情况是没有重复字符返回所有长度或都为重复字符返回1

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        Set<Character> set = new HashSet<>();
        int ans = 0, i = 0, j = 0;
        while (i < n && j < n) {
            // try to extend the range [i, j]
            if (!set.contains(s.charAt(j))){
                set.add(s.charAt(j++));
                ans = Math.max(ans, j - i);
            }
            else {
                set.remove(s.charAt(i++));
            }
        }
        return ans;
    }
}

优化滑动窗口:
优化在于只需要遍历一次即执行 n 次,遍历时判断当前字符是否在集合map中,若存在则将索引 i 赋值集合map中相同字符的 value(该字符索引值) ,然后给结果附上当前窗口大小( j - i + 1)和结果比较的最大值,之后再将当前字符和索引位置加入集合map

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length(), ans = 0;
        Map<Character, Integer> map = new HashMap<>(); // current index of character
        // try to extend the range [i, j]
        for (int j = 0, i = 0; j < n; j++) {
            if (map.containsKey(s.charAt(j))) {
                i = Math.max(map.get(s.charAt(j)), i);
            }
            ans = Math.max(ans, j - i + 1);
            map.put(s.charAt(j), j + 1);
        }
        return ans;
    }
}

7. 整数转换

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
示例 1:
输入: 123
输出: 321
示例 2:
输入: -123
输出: -321
示例 3:
输入: 120
输出: 21
注意:
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。

解题思路:
循环获取最后一位数并对原来的数取余
遇到的问题:
数值可能溢出,则再第七位判断数值的大小是否大于最大数/10的值

class Solution {
    public int reverse(int x) {
        int result = 0;
        int temp = 1 << 31 ;
        while(x != 0){
            if(((result == Integer.MAX_VALUE && (x % 10) > 7) || result > Integer.MAX_VALUE / 10) ||
               ((result == Integer.MIN_VALUE / 10 &&( x % 10) < -8) || result < Integer.MIN_VALUE / 10)){
                return 0;
            }
            temp = result;
            result = result * 10 + x % 10;

            x /= 10;
        }
        return result;
    }
}
执行用时 :1 ms, 在所有 java 提交中击败了100.00%的用户
内存消耗 :33.8 MB, 在所有 java 提交中击败了79.07%的用户

9. 回文数

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

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

本答案搬运自力扣用户MisterBooo的答案:
解读:将整数转为字符串之后反转字符串,再将输入的整数转为字符串和转换的字符串比较

class Solution {
    public boolean isPalindrome(int x) {
    	/**
    	  * x + ""是将int转为String,reverse()将字符串反转,
    	  * toString()将StringBuilder对象转化为String
    	  */
        String reversedStr = (new StringBuilder(x + "")).reverse().toString();
        return (x + "").equals(reversedStr);
    }
}

本答案搬运自力扣用户LeetCode的答案:
解读:根据题意先判断肯定不为回文数的情况:即为负数和整数最后一位为0的情况(除0外)
然后获取输入数的后一半的数值,获取后将该数值和计算后的原数值比较,具体见下方注释

public class Solution {
    public bool IsPalindrome(int x) {
        // 当输入的数为负数或输入的数最后一位是0
        if(x < 0 || (x % 10 == 0 && x != 0)) {
            return false;
        }

		/**
		 * revertedNumber 是输入的数的后一半数值的逆转的数值,如12321最后得到123
		 * 当输入的数大于revertedNumber时revertedNumber再取输入数的最后一位为自身个位
		 * 同时输入的数去掉最后一位数
		 */
        int revertedNumber = 0;
        while(x > revertedNumber) {
            revertedNumber = revertedNumber * 10 + x % 10;
            x /= 10;
        }

		/**
		 * 还要考虑输入的数长度为奇数时的情况
		 * 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber=123
		 * 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。
		 */ 
        return x == revertedNumber || x == revertedNumber/10;
    }
}

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 的范围内。

示例 1:

输入: “III”
输出: 3
示例 2:

输入: “IV”
输出: 4
示例 3:

输入: “IX”
输出: 9
示例 4:

输入: “LVIII”
输出: 58
解释: L = 50, V= 5, III = 3.
示例 5:

输入: “MCMXCIV”
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.

答案来自力扣用户guanpengchn的答案

class Solution {
    public int romanToInt(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 ans = 0;
        for(int i = 0;i < s.length();) {
            if(i + 1 < s.length() && map.containsKey(s.substring(i, i+2))) {
                ans += map.get(s.substring(i, i+2));
                i += 2;
            } else {
                ans += map.get(s.substring(i, i+1));
                i ++;
            }
        }
        return ans;
    }
}
执行用时 :14 ms, 在所有 Java 提交中击败了12.68%的用户
内存消耗 :37.3 MB, 在所有 Java 提交中击败了13.04%的用户

答案来自力扣用户donespeak的答案

class Solution {
    public int romanToInt(String s) {
        int sum = 0;
        int preNum = getValue(s.charAt(0));
        for(int i = 1;i < s.length(); i ++) {
            int num = getValue(s.charAt(i));
            if(preNum < num) {
                sum -= preNum;
            } else {
                sum += preNum;
            }
            preNum = num;
        }
        sum += preNum;
        return sum;
    }
    
    private int getValue(char ch) {
        switch(ch) {
            case 'I': return 1;
            case 'V': return 5;
            case 'X': return 10;
            case 'L': return 50;
            case 'C': return 100;
            case 'D': return 500;
            case 'M': return 1000;
            default: return 0;
        }
    }
}

14. 求最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
示例 1:
输入: [“flower”,“flow”,“flight”]
输出: “fl”
示例 2:
输入: [“dog”,“racecar”,“car”]
输出: “”
解释: 输入不存在公共前缀。
说明:
所有输入只包含小写字母 a-z 。

答案来自力扣用户LeetCode的答案
解读(详解见链接):
比哪里每个字符串数组的成员,遍历时获取当前字符串和后一个字符串的公共部分,若相同部分位置不为0(不在开头)获取该部分字符串,再与下一个比较获取相同部分字符串,最后输出

public String longestCommonPrefix(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;
}

20. 有效的括号

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

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

示例 1:
输入: “()”
输出: true
示例 2:
输入: “()[]{}”
输出: true
示例 3:
输入: “(]”
输出: false
示例 4:
输入: “([)]”
输出: false
示例 5:
输入: “{[]}”
输出: true

答案来自力扣用户LeetCode的答案

class Solution {

  // Hash table that takes care of the mappings.
  private HashMap<Character, Character> mappings;

  // Initialize hash map with mappings. This simply makes the code easier to read.
  public Solution() {
    this.mappings = new HashMap<Character, Character>();
    this.mappings.put(')', '(');
    this.mappings.put('}', '{');
    this.mappings.put(']', '[');
  }

  public boolean isValid(String s) {

    // Initialize a stack to be used in the algorithm.
    Stack<Character> stack = new Stack<Character>();

    for (int i = 0; i < s.length(); i++) {
      char c = s.charAt(i);

      // If the current character is a closing bracket.
      if (this.mappings.containsKey(c)) {

        // Get the top element of the stack. If the stack is empty, set a dummy value of '#'
        char topElement = stack.empty() ? '#' : stack.pop();

        // If the mapping for this bracket doesn't match the stack's top element, return false.
        if (topElement != this.mappings.get(c)) {
          return false;
        }
      } else {
        // If it was an opening bracket, push to the stack.
        stack.push(c);
      }
    }

    // If the stack still contains elements, then it is an invalid expression.
    return stack.isEmpty();
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值