[Leetcode]leetcode1-10题随记

因为leetcode的题号会变动,所以先记录一下每一题对应的内容。

  10 Regular Expression Matching 21.6% Hard
  9 Palindrome Number 30.9% Easy
  8 String to Integer (atoi) 13.3% Easy
  7 Reverse Integer 23.6% Easy
  6 ZigZag Conversion 23.3% Easy
  5 Longest Palindromic Substring 22.5% Medium
  4 Median of Two Sorted Arrays 18.2% Hard
  3 Longest Substring Without Repeating Characters 21.6% Medium
  2 Add Two Numbers 22.3% Medium
  1 Two Sum 21.4% Medium

第一题,寻找给定数组中,相加等于目标数的两个数字的下标。

这道题其实很简单,它限定死了每个测试用例都只有一对符合的,那样只要找到合适的就可以跳出循环结束,同时也方便了第二种算法hashmap时一个key对应一个value。用最暴力的方法两重循环,i从0到length,j从i+1到length算,这样时间复杂度是O(n2)。那么为了减少时间复杂度,牺牲空间复杂度,使用hashmap这个数据结构即可,从头遍历数组,首先使用target number减去当前位置的数字,得到另一个加数的值,在hashmap中查找这一值即可,如果hashmap中不含有当前位置的数字,将当前位置的数字加入hashmap,代码如下:

public class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap map =new HashMap();
        for(int i=0;i<nums.length;i++){
            int num=nums[i];
            int target_num=target-num;
            Object index=map.get(target_num);
            if(index!=null){
                int[] result={(int)index,i};
                    return result;
            }
            map.put(num,i);
        }
        return null;
    }
}

第二题,将两个像链表一样的结构相加。这道题的逻辑很简单,注意特殊情况的处理即可,比如相加后的进位问题,两个链表长度不一样的问题等。

public class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        int flag=0;
        ListNode result=null;
        ListNode tail=null;
        while(true){
            if(l1==null&l2==null&flag==0)
                break;
            int val1=(l1==null)?0:l1.val;
            int val2=(l2==null)?0:l2.val;
            int val=val1+val2+flag;
            flag=val/10;
            val=val%10;
            ListNode node=new ListNode(val);
            if(result==null){
                result=node;
                tail=node;
            }
            else{
                tail.next=node;
                tail=node;
            }
            l1=(l1==null)?null:l1.next;
            l2=(l2==null)?null:l2.next;
        }
        return result;
    }
}

第三题,查找最长的无重复的子串长度。

当然可以两重循环暴力求解,这里选择时间复杂度较低的方法。无重复的子串必定在两个相同字母之间,从头开始遍历字符串,如果遇到前面出现过的字母,则计算当前子串的长度是否超过了记录的最大值,如果超过了则替换,否则从上一次出现的字母+1的位置开始重新查找最长子串。这里需要一个数组来记录某个字母是否出现过了。

这道题中不只是26个字母,因为这里设定的数组长度为256。

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        boolean[] exist=new boolean[256];
        int i=0,j=0;
        int maxLen=0;
        for(int n=0;n<s.length();n++){
            if(exist[s.charAt(n)]){
                maxLen=Math.max(maxLen,j-i);
                for(;i<n;i++){
                    if(s.charAt(n)==s.charAt(i)){
                        i++;
                        break;
                    }
                    else{
                         exist[s.charAt(i)]=false;
                    }
                }
            }
            else{
                exist[s.charAt(n)]=true;
            }
            j++;
        }
        maxLen=Math.max(maxLen,j-i);
        return maxLen;
    }
}

第四题,查找两个已经排好序的数组中的中位数,时间复杂度为O(log(m+n))。

类似算法在英文的算法教程中出现过,本题中我们是要查找这两个数组中第(m+n)/2和第(m+n)/2+1大的数字,实质上为查找第K大的数字。需要注意的一点,数组长度可能小于k/2,此时该数组直接取最大值比较,而另一个数组的比较位置也不是k/2,即分裂点并不一定都是k/2,要考虑全面情况。具体的方法可以见其他专门讲这一部分的blog吧。主要java不像C/C++用指针操作数组方便,因为比起C/C++的实现多了两个参数用来记录当前数组的起始下标。

public class Solution {
    public double findK(int[] nums1, int[] nums2, int k, int n1, int n2,int n1_l,int n2_l){
        //System.out.println(n1+" "+n2+" "+k);
        if(n1_l>n2_l){
            return findK(nums2,nums1,k,n2,n1,n2_l,n1_l);
        }
        if(n1_l==0){
            return nums2[n2+k-1];
        }
        if(k==1){
            return Math.min(nums1[n1], nums2[n2]);
        }
        int point1=Math.min(k/2,n1_l);
        int point2=k-point1;
        if(nums1[n1+point1-1]<nums2[n2+point2-1]){
            return findK(nums1,nums2,k-point1,n1+point1,n2,n1_l-point1,n2_l);
        }
        else if(nums1[n1+point1-1]>nums2[n2+point2-1]){
            return findK(nums1,nums2,k-point2,n1,n2+point2,n1_l,n2_l-point2);
        }
        else{
            return nums1[n1+point1-1];
        }
    }
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int k=nums1.length+nums2.length;
        if(k%2==1){
             return findK(nums1,nums2,k/2+1,0,0,nums1.length,nums2.length);
        }
        else
             return (findK(nums1,nums2,k/2,0,0,nums1.length,nums2.length)+findK(nums1,nums2,k/2+1,0,0,nums1.length,nums2.length))/2;
    }
}

第五题,最长的回文字符串。

这里我用的动态规划,主要原理为,如果i到j是回文的,那么只需要判断i-1和j+1是否相同,若相同,则表明i-1到j+1也是回文的。那么建立一个[i][j]的数组记录即可,当j<i时,本不应该出现这种情况,但是这里默认设置为true,以方便计算其他部分。这里的循环是从j先开始的,并且j=1(循环中i的值需要i+1给出,因此要先计算j)。

public class Solution {
    public String longestPalindrome(String s) {
        int len=s.length();
        int ss=0,tt=0,max=0;
        boolean[][] flag=new boolean [len][len];
        for(int i=0;i<len;i++){
            for(int j=0;j<len;j++){
                if(i>=j)
                    flag[i][j]=true;
                else
                    flag[i][j]=false;
            }
        }
        for(int j=1;j<len;j++){
            for(int i=0;i<j;i++){
                if(s.charAt(i)==s.charAt(j)){
                    flag[i][j]=flag[i+1][j-1];
                    if(flag[i][j]==true&&(j-i+1>max)){
                        ss=i;
                        tt=j;
                        max=j-i+1;
                    }
                }
                else
                    flag[i][j]=false;
            }
        }
        return s.substring(ss,tt+1);
    }
}

第六题,zigzag。

最无脑并且时间高效的方法就是开辟数组,怎么摆的怎么存,最后把数组一个个输出即可。

当然这道题也有一定的规律,比如说第一行和最末行的间距是2*(numRows-1),而其他行的间距是2*(numRows-1)-2*i变化的(i为行号)。

public class Solution {
    public String convert(String s, int numRows) {
        if(s.length()==0||numRows<2)
            return s;
        int m=2*(numRows-1);
        String result="";
        for(int i=0;i<numRows;i++){
            for(int j=i;j<s.length();j+=m){
                result+=s.charAt(j);
                if(i>0&&i<numRows-1){
                    int len=j+m-2*i;
                    if(len<s.length()){
                        result+=s.charAt(len);
                    }
                }
            }
        }
        return result;
    }
}

第七题,数字逆序。

看代码即懂,注意点在于①正负 ②溢出

public class Solution {
    public int reverse(int x) {
        int temp=Math.abs(x);
        int result=0;
        while(temp!=0){
            if (result > (Integer.MAX_VALUE - temp % 10) / 10) {
                return 0;
            }
            int number=temp%10;
            result=result*10+number;
            temp=temp/10;
        }
        int flag=x>0?1:-1;
        return result*flag;
    }
}

第八题,从string转换成int数。

这一题主要是需要考虑多种情况,比如空格、不该出现的字母、溢出等。

public class Solution {
    public int myAtoi(String str) {
        int i=0,sign=1;
        int result=0;
        int MAX=2147483647;
        while(i<str.length()&&str.charAt(i)==‘ ‘){
            i++;
        }
        if(i<str.length()&&str.charAt(i)==‘-‘){
            sign=-1;
            i++;
        }
        else if(i<str.length()&&str.charAt(i)==‘+‘){
            sign=1;
            i++;
        }
        for(;i<str.length();i++){
            if(str.charAt(i)>=‘0‘&&str.charAt(i)<=‘9‘){
                if(sign==1&&result>=(MAX-(str.charAt(i)-‘0‘))/10){
                    return MAX;
                }
                if(sign==-1&&result>(MAX-(str.charAt(i)-‘0‘))/10){
                    return -2147483648;
                }
                result=result*10+(str.charAt(i)-‘0‘);
            }
            else{
                break;
            }
        }
        return result*sign;
    }
}

第九题,判断回文数字,不能用多余的空间。

既然对空间复杂度有要求,那么只能从两边的数字一对对的算出来比较。例如12321,用12321/1000%10得到最高位1,12321/1%10得到最低位,然后使用12321/100%10得到次高位,12321/10%10得到次低位,以此类推。

public class Solution {
        public boolean isPalindrome(int x) {
        if(x==0)
            return true;
        if(x<0)
            return false;
        int bit=0;
        int temp=Math.abs(x);
        while(temp!=0){
            bit++;
            temp/=10;
        }
        int point1=1;
        int point2=(int) Math.pow(10, bit-1);
        while(point1<point2){
            if(x/point1%10!=x/point2%10){
                return false;
            }
            point1*=10;
            point2/=10;
        }
        return true;
    }
}

第十题,正则表达式。虽然写出来行数不多,但是这个题目本身还是有些难度的,要考虑的特殊情况比较多。此处有两种方法。

第一种是采用纯递归的方法,在没有*的情况下都很简单,一旦存在了*,需要考虑全面,比如说(aaab a*ab),这里a*匹配几个都需要尝试,那么递归时需要尝试(aab ab)(ab ab)(b ab)是否能有匹配的,如果有再继续匹配后面的,一直到字符串结束。这个方法时间复杂度极高。

public class Solution {
    public boolean isMatch(String s, String p) {
        if(p.length()==0){
            return s.length()==0;
        }
        if((p.length()>1&&p.charAt(1)!=‘*‘)||p.length()==1){
            if(s.length()!=0&&(s.charAt(0)==p.charAt(0)||p.charAt(0)==‘.‘))
                return isMatch(s.substring(1),p.substring(1));
            else
                return false;
        }
        else{
            int i=0;
            while(s.length()-i>0&&(s.charAt(i)==p.charAt(0)||p.charAt(0)==‘.‘)){
              if(isMatch(s.substring(i),p.substring(2)))
                    return true;
                i++;
            }
            return (isMatch(s.substring(i),p.substring(2)));
        }
    }
}

第二种方法还是动态规划,采用一个二维数组记录,f[i][j]表示s[0...i-1]和p[0...j-1]匹配,那么当p[j-1]不为*时,f[i][j]=f[i-1][j-1]&&s[i-1]==p[j-1];当p[j-1]为*时,设p[j-2]为x,f[i][j]在满足以下条件时为true:①x重复了0次并且f[i][j-2]为true;②x重复了至少一次,满足了x*x的模式,即s[i-1]==x并且f[i-1][j]为true。该方法时间复杂度较低。

public class Solution {
    public boolean isMatch(String s, String p) {
        int m=s.length(),n=p.length();
        boolean[][] f=new boolean[m+1][n+1];

        f[0][0]=true;
        for(int i=1;i<=m;i++){
            f[i][0]=false;
        }
        for(int j=1;j<=n;j++){
            f[0][j]=j>1&&p.charAt(j-1)==‘*‘&&f[0][j-2];
        }
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                if(p.charAt(j-1)!=‘*‘)
                      f[i][j] = f[i - 1][j - 1] && (s.charAt(i-1)== p.charAt(j-1)|| p.charAt(j-1)==‘.‘);
                else
                      f[i][j] = f[i][j - 2] || (s.charAt(i-1) ==  p.charAt(j-2) || p.charAt(j-2)==‘.‘) && f[i - 1][j];

            }
        }
        return f[m][n];
    }
}

时间: 2024-11-06 14:15:01

[Leetcode]leetcode1-10题随记的相关文章

LeetCode第[10]题(Java):Regular Expression Matching

题目:匹配正则表达式 题目难度:hard 题目内容:Implement regular expression matching with support for '.' and '*'. '.' Matches any single character. '*' Matches zero or more of the preceding element. The matching should cover the entire input string (not partial). The fu

Leetcode第1题至第10题 思路分析及C++实现

笔者按照目录刷题,对于每一道题,力争使用效率最高(时间复杂度最低)的算法,并全部通过C++代码实现AC.(文中计算的复杂度都是最坏情况复杂度) 因为考虑到大部分读者已经在Leetcode浏览过题目了,所以每道题都按照 解题思路 -> 实现代码 -> 问题描述 的顺序进行讲解. (笔者目前已刷 40 题,已更新解法 10 题,最近一段时间会频繁更新)可以点击下方链接,直达gitbook: https://codernie.gitbooks.io/leetcode-solutions/conten

leetcode第9题-Palindrom Number

这是leetcode的第九题,相对来说比较简单,目的很简单,就是判断一个int型的数是不是回文数.但是有几点需要考虑: 负数应该没有回文数,要加判断!要注意额外的空间申请问题.判断是否是回文数势必要对一个数进行反转,反转的时候就要考虑溢出的问题.实现的代码如下: #include<stdio.h> bool isPalindrom(int x) { if(x<0) return false; else { int tmp=x; int sum=0; while(tmp) { sum=su

LeetCode第四题,Add Two Numbers

题目原文: You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. Input: (2 -> 4 -> 3) + (5 -> 6

LeetCode 第 371 题 (Sum of Two Integers)

LeetCode 第 371 题 (Sum of Two Integers) Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -. Example: Given a = 1 and b = 2, return 3. 不用加减法计算两个整数的和.这道题其实是考察一些基本的布尔代数知识.我们知道,二进制表示时: 0 + 0 = 00 1 + 0 = 01 0 +

LeetCode第五题,Longest Palindromic Substring

题目原文: Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. 题意解析: 最长回文子串.就是给定一个字符串S,找出其中的最长回文子串,并返回该子串. 解法: 第一种方法显然是循环暴力枚举,复杂度为O(

【LeetCode每天一题】3Sum(三数之和)

Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero. Note: The solution set must not contain duplicate triplets. Example: Given array nums =

LeetCode开心刷题五十一天——118. Pascal&#39;s Triangle 接触跳转表概念,不知用处 lamda逗号导致表达式加法奇怪不理解119. Pascal&#39;s Triangle II

118. Pascal's Triangle Easy 87984FavoriteShare Given a non-negative integer numRows, generate the first numRows of Pascal's triangle. In Pascal's triangle, each number is the sum of the two numbers directly above it. Example: Input: 5 Output: [ [1],

LeetCode 第6题 Z字型变换

LeetCode 第6题 Z字型变换 题目描述 将一个给定字符串根据给定的行数,以从上往下.从左到右进行?Z 字形排列. 比如输入字符串为 "LEETCODEASHARANG"?行数为 3 时,排列如下: L???C???A???R E?T?O?E?S?A?A?G E???D???H???N 之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCARETOESAAGEDHN". 请你实现这个将字符串进行指定行数变换的函数: string conver

LeetCode 第 73 题 (Set Matrix Zeroes)

LeetCode 第 73 题 (Set Matrix Zeroes) Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place. Follow up: Did you use extra space? A straight forward solution using O(mn) space is probably a bad idea. A simple impro