10.28 LeetCode周总结(1~7题)

10.28 LeetCode周总结

1、两数之和

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

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

(1)此题首先想到的就是暴力法,时间复杂度是O(n^2)
(2)更巧妙的是用map,利用键值对,只需O(n)

class Solution {
    public int[] twoSum(int[] nums, int target) {
        
        Map<Integer,Integer> map=new HashMap<>();
        for(int i=0;i<nums.length;i++){
            int a=target-nums[i];
            //判断是否存在此键
            if(map.containsKey(a)){
            	//若存在,则返回键的值,和i
                return new int[]{map.get(a),i};
            }
            map.put(nums[i],i);
        }
        System.out.println("No");
        return new int[]{-1,-1};
        
    }
}
2、两数相加

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

示例:

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

循环实现:

struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
    int a=0;
    struct ListNode *head,*cur,*next;
    head=(struct ListNode *)malloc(sizeof(struct ListNode));
    head->next=NULL;
    cur=head;
    while(l1||l2||a){
        next=(struct ListNode *)malloc(sizeof(struct ListNode));
        next->next=NULL;
        cur->next=next;
        cur=next;
        l1!=NULL?(a+=l1->val,l1=l1->next):(a+=0);
        l2!=NULL?(a+=l2->val,l2=l2->next):(a+=0);
        int b=a%10;
        next->val=b;
        a=a/10;
        
    }
    
    return head->next;
}

递归实现:

int c=0;
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
    if(l1==NULL&&l2==NULL&&c==0)
        return NULL;
    l1!=NULL?(c+=l1->val,l1=l1->next):(c+=0);
    l2!=NULL?(c+=l2->val,l2=l2->next):(c+=0);
    struct ListNode *p=(struct ListNode *)malloc(sizeof(struct ListNode));
    
    int a=c%10;
    c=c/10;
    p->val=a;
    p->next=addTwoNumbers(l1,l2);
    return p;
}
3.无重复字符的最长子串长度

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

示例:

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

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

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

(1)暴力法:
(2)滑动窗口
通过使用 HashSet 作为滑动窗口,我们可以用 O(1)的时间来完成对字符是否在当前的子字符串中的检查。

滑动窗口是数组/字符串问题中常用的抽象概念。 窗口通常是在数组/字符串中由开始和结束索引定义的一系列元素的集合,即 [i,j)左闭,右开)。而滑动窗口是可以将两个边界向某一方向“滑动”的窗口。例如,我们将 [i,j) 向右滑动 1 个元素,则它将变为 [i+1,j+1)(左闭,右开)。

回到我们的问题,我们使用 HashSet 将字符存储在当前窗口 [i,j)(最初 j=i)中。 然后我们向右侧滑动索引 j,如果它不在 HashSet 中,我们会继续滑动 j。直到 s[j] 已经存在于 HashSet 中。此时,我们找到的没有重复字符的最长子字符串将会以索引 i开头。如果我们对所有的 iii 这样做,就可以得到答案。

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;
} 
}

时间复杂度O(n)

(3)优化的滑动窗口:
上述的方法最多需要执行 2n 个步骤。事实上,它可以被进一步优化为仅需要 n 个步骤。我们可以定义字符到索引的映射,而不是使用集合来判断一个字符是否存在。 当我们找到重复的字符时,我们可以立即跳过该窗口。

也就是说,如果 s[j] 在 [i,j) 范围内有与 j′重复的字符,我们不需要逐渐增加 iii 。 我们可以直接跳过 [i,j′] 范围内的所有元素,并将 iii 变为 j′+1。
使用HashMap

class Solution {
    public int lengthOfLongestSubstring(String s) {
        
       Map<Character,Integer> map=new HashMap<>();
        int i=0,j=0;
        int sum=0;
        int n=s.length();
        for(j=0;j<n;j++){
            if(map.containsKey(s.charAt(j))){
                i=Math.max(i,map.get(s.charAt(j))+1);
            }
            sum=Math.max(sum,j-i+1);
            map.put(s.charAt(j),j);
            
        }
        return sum;
        
    }
}
4、寻找两个有序数组的中位数

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。

示例:

nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0


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

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

看之前的笔记,有这一篇

5、最长回文子串

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

示例:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

输入: "cbbd"
输出: "bb"

使用的"马拉车算法",前面文章也有讲解

class Solution {
    public String longestPalindrome(String s) {
        
        String str="";
        for(int i=0;i<s.length();i++){
             str=str+"#"+s.charAt(i);
        }
        str=str+"#";
        int[] pl=new int[2005];
        int pos=0;
        int Right=0;
        pl[0]=1;
        for(int i=1;i<str.length();i++){
            if(i<=Right){
                int j=2*pos-i;
                int aa=Right-i;
                pl[i]=Math.min(pl[j],aa);
                if(pl[i]==0)
                    pl[i]=1;
                int r=i+pl[i];
                int l=i-pl[i];
                while(r<str.length() && l>-1){
                    if(str.charAt(r)==str.charAt(l)){
                        r++;
                        l--;
                        pl[i]++;
                    }
                    else{
                        break;
                    }
                }
                if(i+pl[i]-1>Right){
                    Right=i+pl[i]-1;
                    pos=i;
                }
                
            }
            else{
                pl[i]=1;
                int r=i+1;
                int l=i-1;
                while(r<str.length() && l>-1){
                    if(str.charAt(r)==str.charAt(l)){
                        r++;
                        l--;
                        pl[i]++;
                    }
                    else{
                        break;
                    }
                }
                pos=i;
                Right=i+pl[i]-1;
                
            }
        }
        
       int max=0;
        int j=0;
        for(int i=0;i<str.length();i++) {
        	if(max<pl[i]){
        		max=pl[i];
        		j=i;
        	}
        }
        max=max-1;
        int k1=j+1;
        int k2=j-1;
        String str1=str.charAt(j)+"";
        for(int i=1;i<=max;i++) {
        	str1=str.charAt(k2)+str1+str.charAt(k1);
        	k1++;
        	k2--;
        }
        str1=str1.replace("#","");
        return str1;
        
        
    }
}

6、Z字形变换

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:

L   C   I   R
E T O E S I I G
E   D   H   N

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”。

示例:

输入: s = "LEETCODEISHIRING", numRows = 3
输出: "LCIRETOESIIGEDHN"


输入: 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) {
        if(numRows==1){
            return s;
        }
        List<StringBuffer> list=new ArrayList<>();
        for(int i=0;i<numRows;i++){
            list.add(new StringBuffer());
        }
        int flag=1;
        int current=1;
        list.get(0).append(s.charAt(0));
        for(int i=1;i<s.length();i++){
            list.get(current).append(s.charAt(i));
            if(current==0){
                current=1;
                flag=1;
            }
                
            else if(current==numRows-1){
                 current=numRows-2;
                 flag=-1;
            }
            else{
                if(flag==1)
                    current=current+1;
                else
                    current=current-1;
            }
               
        }
        String str="";
        for(int i=0;i<numRows;i++){
            str=str+list.get(i).toString();
        }
        return str;
    }
}

注:
(1)flag和current用的好 ,flag表示是向上走还是向下走,current表示当前行
(2)向字符串中添加一个字符,用StringBuffer比较简单,可以直接使用append()方法,而string中如此方法,最后别忘了再转换成 string就行

7、整数反转

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。

示例:

输入: 123
输出: 321

输入: -123
输出: -321

输入: 120
输出: 21

注意:

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

注:此题关键点在于反转后的数可能超出整数范围
(1)使用java字符串的反转进行,通过异常来判断反转所得的数是否异常

class Solution {
    public int reverse(int x) {
        
        int a,b;
	     int c=(int)Math.pow(2,31);
	     a=c-2*c;
	        b=c-1;
	        if(x<a || x>b){
	            return 0;
	        }
	        String str=String.valueOf(x);
	        String str1="";
	        String str2="";
	        if(x<0){
	            str1="-"+str1;
	            str2=str.substring(1);
	        }else{
	            str2=str.substring(0);
	        }
	        StringBuffer str3=new StringBuffer(str2);
	        String str4=str3.reverse().toString();
	        str1=str1+str4;
	        try {
	        	 int d=Integer.parseInt(str1);
	        	 return d;
	        }catch (Exception e) {
				return 0;
			}
    }
}

(2)正规的C语言实现

int reverse(int x){
    
    /*
    溢出条件有两个,一个是大于整数最大值MAX_VALUE,另一个是小于整数最小值MIN_VALUE,设当前计算结果为ans,下一位为       pop。
    (1)从ans * 10 + pop > MAX_VALUE这个溢出条件来看

    当出现 ans > MAX_VALUE / 10 且 还有pop需要添加 时,则一定溢出
    当出现 ans == MAX_VALUE / 10 且 pop > 7 时,则一定溢出,7是2^31 - 1的个位数

    (2)从ans * 10 + pop < MIN_VALUE这个溢出条件来看

    当出现 ans < MIN_VALUE / 10 且 还有pop需要添加 时,则一定溢出
    当出现 ans == MIN_VALUE / 10 且 pop < -8 时,则一定溢出,8是-2^31的个位数
    
    */
    
    int a=0;
    int b;
    int xx=x;
    int h=(int)pow(2,31);
    int h1=h-2*h;
    int h2=h-1;
    while(xx){
        b=xx%10;
        if(a>h2/10 ||(a==h2/10 && b>7))
            return 0;
        if(a<h1/10 || (a==h1/10 && b<-8))
            return 0;
        a=a*10+b;
        xx=xx/10;
    }
    return a;
    

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值