LeetCode分析与题解 11-20

Leetcode11 盛最多水的容器

给定 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i
的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。

在这里插入图片描述

图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例:

输入: [1,8,6,2,5,4,8,3,7] 输出: 49

思路:一开始我用暴力法直接解题,然后一顿操作猛如虎。一看打败的人只有百分之三十。。。也对,怎么可能暴力法是最优解呢。。

这道题可以用双指针法完成,一个指针指向最初的端点,一个指向最后,然后把两个指针向中央移动,并不断更新最大值,这样在指针碰撞之前,我们能够得到一个最大值,该值为我们所求。有一点需要注意,我们把指针向中央移动时,移动的是比较短的那个。为什么呢?我们都知道,面积为长度与宽度之积。随着指针向中央移动,其长度必定递减,为求更大的面积,我们必须要求更大的宽度。而我们又知,所求的宽度取决于更短的那个(木桶原理),若要宽度增大,我们唯有移动更短的端点,唯有这样才有使宽度增大的希望,才有使面积增大的希望。

class Solution {
    public int maxArea(int[] height) {
        int i = 0,j = height.length - 1,max = 0,now = 0;
        while(i != j){
            now = (j - i) * Math.min(height[i],height[j]);
            max = max > now ? max : now;
            if(height[i] >= height[j]){
                j--;
            }else{
                i++;
            }
        }
        return max;
    }
}

Leetcode12 整数转罗马数字

罗马数字包含以下七种字符: 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:

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

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

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

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

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

class Solution {
    public String intToRoman(int num) {
        String[] array = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
        int[] number = {1000,900,500,400,100,90,50,40,10,9,5,4,1};
        int i = 0;
        String get = "";
        while(i <= 12){
            if(num >= number[i]){
                num -= number[i];
                get += array[i];
            }else{
                i++;
            }
        }
        return get;
    }
}

Leetcode13 罗马数字转整数

罗马数字包含以下七种字符: 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.

class Solution {
    public int romanToInt(String s) {
        String[] array = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
        int[] number = {1000,900,500,400,100,90,50,40,10,9,5,4,1};
        int i = 0,num = 0;
        while(!s.equals("")){
            if(s.startsWith(array[i])){
                s = s.substring((array[i]).length());
                num += number[i];
            }else{
                i++;
            }
        }
        return num;
    }
}

Leetcode14 最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 “”。

示例 1:

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

输入: [“dog”,“racecar”,“car”] 输出: “”
解释: 输入不存在公共前缀。
说明:

所有输入只包含小写字母 a-z 。

解析:遍历每一个字符串,比较当前最大公共前缀的字符串与当前字符串是否相等,不相等则更新最大公共前缀的字符串即可。

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if(strs == null || strs.length == 0){
            return "";
        }
        
        String max = strs[0];//最长公共前缀
        int num = strs[0].length();//最长公共前缀的长度
        int length = 0;//当前遍历的字符串长度与最长公共前缀的长度最小值
        int i,j;
        
        for(i = 1;i < strs.length;i++){
            length = strs[i].length() > num ? num : strs[i].length();
            for(j = 0;j < length;j++){
                if(max.charAt(j) != strs[i].charAt(j)){
                    max = max.substring(0,j);
                    if(max.equals("")){
                        return "";
                    }
                    num = j;
                    break;
                }
            }
            if(num > j) {
            	max = max.substring(0,j);
            	num = j;
            }
        }
        return max;
    }
}

Leetcode15 三数之和

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0
?找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]

解析:使用双指针法,由于要取三数之和,可以先将数组排序,然后遍历数组取出第一个数字,然后建立两个指针,分别指向第一个数字之后的一个数字和最后一个数字,判断三数之和是否为0,是则添加至链表,否则继续移动双指针,注意判断边界条件和去重即可。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> list = new ArrayList<List<Integer>>();
        
        if(nums == null){
            return null;
        }else if(nums.length < 3){
            return list;
        }
        
        int j,k;
        Arrays.sort(nums);//排序
        
        for(int i = 0;i < nums.length - 2;i++){
            if(nums[i] > 0){//首数字大于0,易知三数之和不可能等于0
                break;
            }
            if(i > 0 && nums[i] == nums[i-1]){//去重
                continue;
            }

            j = i + 1;
            k = nums.length - 1;
            while(j < k){
                if(nums[i] + nums[j] + nums[k] == 0){
                    if(j > i + 1 && nums[j] == nums[j-1]){//去重
                        j++;
                    }else if(k < nums.length - 1 && nums[k] == nums[k+1]){//去重
                        k--;
                    }else{
                        list.add(Arrays.asList(nums[i],nums[j],nums[k]));
                        j++;
                        k--;
                    }
                }else if(nums[i] + nums[j] + nums[k] > 0 && j < k - 1){
                    k--;
                }else if(nums[i] + nums[j] + nums[k] < 0 && j < k - 1){
                    j++;
                }else {
                	break;
                }
            }
            
        }
        
        return list;
    }
}

Leetcode16 最接近的三数之和

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).

解析:这一题运用双指针法可以轻松解决,由于这一题与上题十分相似,故不重复解题思路了。

class Solution {
    public int threeSumClosest(int[] nums, int target) {
		Arrays.sort(nums);//排序
        int j,k,num = nums[0] + nums[1] + nums[nums.length-1];//num为三数之和
  
        for(int i = 0;i < nums.length - 2;i++){
            if(i > 0 && nums[i] == nums[i-1]){//去重
                continue;
            }
            j = i + 1;
            k = nums.length - 1;
            while(j < k){
                
                int sum = nums[i] + nums[j] + nums[k];
                if(Math.abs(target - sum) < Math.abs(target - num)) {
                	num = sum;
                }
                
                if(sum > target) {
                	k--;
                }else if(sum < target) {
                	j++;
                }else {
                	return target;
                }
            }
            
        }
        
        return num;
    }
}

Leetcode17 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

在这里插入图片描述

示例:
输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

解析:实话实说,这道题挺简单的,真的没啥好说的。。。

class Solution {
    public List<String> letterCombinations(String digits) {
        List<String> list = new ArrayList<String>();
        
        if(digits == null){
            return null;
        }else if(digits.length() == 0){
            return list;
        }
        
        char[] chArray = digits.toCharArray();
        char[][] getArray = {{'a','b','c'},{'d','e','f'},{'g','h','i'},{'j','k','l'},{'m','n','o'},{'p','q','r','s'},{'t','u','v'},{'w','x','y','z'}};
        int[] x = new int[chArray.length];
        int all = 1;
        
        for(int i = 0;i < chArray.length;i++){
            if(chArray[i] == '7' || chArray[i] == '9'){
                all *= 4;
                x[i] = 4;
            }else{
                all *= 3;
                x[i] = 3;
            }
        }
        
        int least = all,j,k,num;
        char[][] arr = new char[all][chArray.length];

        for(int i = 0;i < chArray.length;i++){
            least /= x[i];
            num = least;
            j = 0;
            k = 0;
            while(j < all){
                for(;j < num;j++){
                    arr[j][i] = getArray[chArray[i] - '2'][k];
                }
                num += least; 
                k = k == x[i] - 1 ? 0 : k + 1;
            }
        }
        
        for(int i = 0;i < all;i++){
            list.add(new String(arr[i]));
        }
        
        return list;
    }
}

Leetcode19 删除链表的倒数第N个节点

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。

解析:使用快慢指针

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode left = head,right = head,p = null;//p为left的前一个节点
        int i = 0;
        while(right.next != null){
            right = right.next;
            if(++i >= n){
                p = left;
                left = left.next;            
            }
        }
        //left为要删除的节点
        if(p == null){
            return head.next;
        }else{
            p.next = left.next;
        }
        return head;
    }
}

Leetcode20 有效的括号

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: “()”
输出: true
示例 2:
输入: “()[]{}”
输出: true
示例 3:
输入: “(]”
输出: false
示例 4:
输入: “([)]”
输出: false
示例 5:
输入: “{[]}”
输出: true

解析:堆栈的基本应用

class Solution {
    public boolean isValid(String s) {
        if(s.length() == 0){
            return true;
        }
        
        Stack<Character> stack = new Stack<Character>();
        char[] charArray = s.toCharArray(); 
        for(int i = 0;i < charArray.length;i++){
            if(charArray[i] == '(' || charArray[i] == '{' || charArray[i] == '['){
                stack.push(charArray[i]);
            }else if(charArray[i] == ')'){
                if(stack.empty() || stack.pop() != '('){
                    return false;
                }
            }else if(charArray[i] == '}'){
                if(stack.empty() || stack.pop() != '{'){
                    return false;
                }
            }else if(charArray[i] == ']'){
                if(stack.empty() || stack.pop() != '['){
                    return false;
                }
            }
        }
        if(stack.empty()){
            return true;
        }
        return false;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值