LeetCode分析与题解 1-10

LeetCode 01 两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1]

分析:要让时间复杂度为O(n),便想到了哈希表,典型的空间换时间。首先我们建立一个哈希表,以值查询索引。然后开始一趟遍历,将target与此趟遍历所得元素相减,就是我们所求元素,判断它是否在表中即可。还有一个需要注意的地方,就是需要判断本趟遍历的索引与哈希所得的索引是否相同,若相同则应舍弃(比如2加2虽然等于4,但就是自己加自己,肯定不符合题意)

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] array = {0,0};
		HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
		
		for(int i=0;i<nums.length;i++) {
			map.put(nums[i], i);
		}
		
		for(int i=0;i<nums.length;i++) {
			if(map.containsKey(target - nums[i]) && i != map.get(target - nums[i])) {
				array[0] = i;
				array[1] = map.get(target - nums[i]);
				return array;
			}
		}
		
		return null;
    }
}

LeetCode 02 两数相加

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

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

分析:送分题。。。对着ListNode做一趟遍历即可,不过需要注意两个链表长度相同并且最后一次相加时要进位的特殊情况。

/**
 * 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 node = new ListNode(-1),use = node;
        boolean first = true;//始位保存标志
        boolean add = false;//进位标志
        int num;//当前位置的值
        while(l1!=null && l2!=null){
            num = l1.val + l2.val;
            if(add)
                num++;
            add = false;
            if(num > 9){
                num -= 10;
                add = true;
            }
            if(first){
                use = new ListNode(num);
                first = false;
                node = use;
            }else{
                use.next = new ListNode(num);
                use = use.next;
            }
            l1 = l1.next;
            l2 = l2.next;
        }
        
        while(l1!=null){
            num = l1.val;
            if(add)
                num ++;
            add = false;
            if(num > 9){
                num -= 10;
                add = true;
            }
            try{
                use.next = new ListNode(num);
            }catch(Exception e){}
            use = use.next;
            l1 = l1.next;
        }
        
        while(l2!=null){
            num = l2.val;
            if(add)
                num ++;
            add = false;
            if(num > 9){
                num -= 10;
                add = true;
            }
            try{
                use.next = new ListNode(num);
            }catch(Exception e){}
            use = use.next;
            l2 = l2.next;
        }
        
        if(add){
            try{
                use.next = new ListNode(1);
            }catch(Exception e){}
        }
              
        return node;
    }
}

官方答案:(比我的简洁多了。。。逃)

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    ListNode dummyHead = new ListNode(0);
    ListNode p = l1, q = l2, curr = dummyHead;
    int carry = 0;
    while (p != null || q != null) {
        int x = (p != null) ? p.val : 0;
        int y = (q != null) ? q.val : 0;
        int sum = carry + x + y;
        carry = sum / 10;
        curr.next = new ListNode(sum % 10);
        curr = curr.next;
        if (p != null) p = p.next;
        if (q != null) q = q.next;
    }
    if (carry > 0) {
        curr.next = new ListNode(carry);
    }
    return dummyHead.next;
}

LeetCode 03 无重复字符的最长子串

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:
输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

分析:典型要用到哈希表辅助啦,遍历字符数组,判断是否在哈希表内,若不在则插入,否则判断当前字符是否与当前的最大子序列有重复,有重复就重设当前最大子序列,没有就当前子序列递增,最后更新最大子序列就行了,挺简单的。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int maxLength = 0, nowLength = 0;
        char[] array = s.toCharArray();
        HashMap<Character,Integer> map = new HashMap<Character,Integer>();
        for(int i=0;i<array.length;i++){
            char c = array[i];
            if(!map.containsKey(c) || nowLength+1<=i-map.get(c)){
                map.put(c,i);
                  nowLength++;
            }else if(nowLength+1>i-map.get(c)){
                nowLength = i-map.get(c);
                map.put(c,i);
            }
            
            if(nowLength > maxLength)
                maxLength = nowLength;
        }
        return maxLength;
    }
}

LeetCode 04 寻找两个有序数组的中位数

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。

请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

示例 1:

nums1 = [1, 3]
nums2 = [2]

则中位数是 2.0
示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

则中位数是 (2 + 3)/2 = 2.5

分析:这道题用到分治法,二分查找法,设有一条线将nums1和nums2两个数组一分为二,由于我们求得是中位数,所以我们控制变量,设nums1划线的节点索引为i,则可根据中位数公式推出nums2划线的节点索引可以用i的公式表示,然后的步骤跟二分查找大同小异了,注意做好边界检查,这道题的边界检查还是比较复杂的。

 		  left_part          |        right_part
    A[0], A[1], ..., A[i-1]  |  A[i], A[i+1], ..., A[m-1]
    B[0], B[1], ..., B[j-1]  |  B[j], B[j+1], ..., B[n-1]
class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        if(nums1.length > nums2.length) {
			int[] temp = nums1;
			nums1 = nums2;
			nums2 = temp;
		}
		
		int m = nums1.length;
		int n = nums2.length;
		int iMin = 0,iMax = m,j,i;
		
		while(iMax >= iMin) {
			i = (iMin + iMax)/2;
			j = (m + n + 1)/2 - i;
			if(i < iMax && j > 0 && nums1[i] < nums2[j-1]) {
				iMin = i + 1;
			}else if(i > iMin && j < n && nums2[j] < nums1[i-1]) {
				iMax = i - 1; 
			}else {
				int maxLeft,minRight;
				if(i < 1) {
					maxLeft = nums2[j-1];
				}else if(j < 1) {
					maxLeft = nums1[i-1];
				}else {
					maxLeft = nums1[i-1] > nums2[j-1] ? nums1[i-1] : nums2[j-1];
				}
				
				if((n + m) % 2 == 1) {
					return (double)maxLeft;
				}
                
                if(i >= m) {
					minRight = nums2[j];
				}else if(j >= n) {
					minRight = nums1[i];
				}else {
					minRight = nums1[i] > nums2[j] ? nums2[j] : nums1[i];
				}
                
                if((n + m) % 2 == 0) {
					return (minRight + maxLeft)/2.0;
				}
			}
		}
        return 0.0;
    }
}

LeetCode 05 最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”

分析:额怎么说呢。。用动态规划来做这道题目还是挺简单的吧。。状态转移方程如下所示,注意一下边界条件就好了。
在这里插入图片描述

class Solution {
    public String longestPalindrome(String s) {
        char[] array = s.toCharArray();
        int size = s.length();
        int largest = 1;//最长回文子串的长度
        int start = 0;//最长回文子串的开始位置
        
        if(size == 0){
            return "";
        }else if(size == 1){
            return s;
        }
        
        int[][] dp = new int[size][size];//动态规划数组
        
        //初始化
        for(int i=0;i<size;i++){
            dp[i][i] = 1;
            if(i < size - 1 && array[i] == array[i+1]){
                dp[i][i+1] = 1;
                largest = 2;
                start = i;
            }
        }
        
        for(int i = 3;i <= size;i++){//当前最长回文子串的长度
            for(int j = 0;j + i <= size;j++){//当前最长回文子串的初始位置
                int end = j + i -1;//当前最长回文子串的结束位置
                if(array[j] == array[end] && dp[j+1][end-1] == 1){
                    dp[j][end] = 1;
                    start = j;
                    largest = i;
                }
            }
        }
        
        return s.substring(start,largest + start);
    }
}

LeetCode 06 Z 字形变换

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:
输入: s = “LEETCODEISHIRING”, numRows = 3
输出: “LCIRETOESIIGEDHN”
示例 2:
输入: s = “LEETCODEISHIRING”, numRows = 4
输出: “LDREOEIIECIHNTSG”
解释:
L D R
E O E I I
E C I H N
T S G

分析:这个真的没啥好分析的,直接上代码吧。

class Solution {
    public String convert(String s, int numRows) {
        String[] stringArray = new String [numRows];
        char[] charArray = s.toCharArray();
        int size = charArray.length;
        int i = 0;//遍历每一个字符
        int k = 0;//遍历每一行
        String end = "";//最终结果
        
        //初始化
        for(int j = 0;j < numRows;j++){
            stringArray[j] = "";
        }
        
        while(i < size){
            for(k = 0;k < numRows && i < size;k++,i++){
                stringArray[k] += charArray[i];
            }
            
            if(i < size){
                for(k = numRows - 2;k > 0 && i < size;k--,i++){
                   stringArray[k] += charArray[i];
                }
            }
        }
        
        for(int j = 0;j < numRows;j++){
            end += stringArray[j];
        }
        
        return end;
    }
}

LeetCode 07 整数反转

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

分析:这道题其实并不难,注意将传入的整数按位翻转即可,不过要注意得到的最终结果可能会溢出,这里我提供一种方法仅供参考,可以一开始将结果值的数据类型设为long,保证其不会发生溢出,再进行判断,如果数据类型为int时是否会发生溢出,是则返回0,否则返回翻转之后的结果,注意数据类型要从long转变为int

class Solution {
    public int reverse(int x) {
        long y = 0;//反转之后的结果
        
        while(x != 0){
            y = y * 10 + x % 10;
            x /= 10;
        }

        if(y < Math.pow(-2,31) || y >= Math.pow(2,31)){
            return 0;
        }
        
        return (int)y;
    }
}

LeetCode 08 字符串转换整数 (atoi)

请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
说明:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,qing返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
示例 1:
输入: “42”
输出: 42
示例 2:
输入: " -42"
输出: -42
解释: 第一个非空白字符为 ‘-’, 它是一个负号。
我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:
输入: “4193 with words”
输出: 4193
解释: 转换截止于数字 ‘3’ ,因为它的下一个字符不为数字。
示例 4:
输入: “words and 987”
输出: 0
解释: 第一个非空字符是 ‘w’, 但它不是数字或正、负号。
因此无法执行有效的转换。
示例 5:
输入: “-91283472332”
输出: -2147483648
解释: 数字 “-91283472332” 超过 32 位有符号整数范围。
因此返回 INT_MIN (−231) 。

分析:这道题的判断条件稍微有点多,但是最本质的实现与上面那道题是相同的,注意一下条件判断与类型变换即可

class Solution {
    public int myAtoi(String str) {
	    if(str == null){
	        return 0;
	    }
	        
	    char[] array = str.toCharArray();
	    int size = str.length();
	    long end = 0;//最终结果
	    int i = 0;//当前遍历的位数
	    int k = 1;//符号位,默认为正数
	    int u = 0;//每一次与end相加的个位数
	        
	    while(i < size){
	        if(array[i] == ' '){
	            i++;
	        }else if(array[i] == '+' || array[i] == '0'){
	            i++;
	            break;
	        }else if(array[i] == '-'){
	            i++;
	            k = -1;
	            break;
	        }else if(array[i] > '0' && array[i] <= '9'){
	            break;
	        }else{
	            return 0;
	        }
	    }
	        
	    if(i == size){
	        return 0;
	    }
	        
	    while(i < size){
            if(k == 1){
	            u = (int)array[i] - (int)'0';
	        }else{
	            u = (int)'0' - (int)array[i];
	        }
                
	        if(array[i] >= '0' && array[i] <= '9'){
	            if(end * 10 + u >= (long)(Math.pow(2,31))){
	                return (int)(Math.pow(2,31));
	            }else if(end * 10 + u < (long)(Math.pow(-2,31))){
	                return (int)(Math.pow(-2,31));
	            }
	                
	            end = end * 10 + u;
	                
	            i++;
	        }else{
	            break;
	        }
	    }

	    return (int)end;
	}
}

LeetCode 09 回文数

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
示例 1:
输入: 121
输出: true
示例 2:
输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:
输入: 10
输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数。

class Solution {
    public boolean isPalindrome(int x) {
        String s = String.valueOf(x);
        char[] array = s.toCharArray();
        int size = array.length;
        
        for(int i = 0,j = size - 1;i < size / 2;i++,j--){
            if(array[i] != array[j]){
                return false;
            }
        }
        
        return true;
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值