[leetcode]题解+经验总结 自己做法+评论区mostvotes汇总 (只包含部分easy难度)

鉴于最近是实习季,可能有很多小伙伴在刷leetcode,我把easy部分刷到的一些有趣的题和大家分享下,也是为了复习总结下,每道题都包含了我自己的做法和评论区 Most Votes的做法,有些做法真令人眼前一亮,大家可以参考下。

注:我题目的顺序是按通过率排序的,如果你想找特定的题,可以尝试ctrl+f搜索题号。


0.leetcode 

教给我们最重要的就是一定一定一定要考虑特殊值情况,值为0?值为null?可不可能为负数?可不可能相加过程中产生溢出?不注意到这些细节问题,你几乎一道题也过不了。


283. move zeroes

题意如下

For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0].

不要笨笨的去交换,选择效率最大的方法:维护个指针把不是零的依次写入 然后后边全赋值为0,注意此操作就地就可以完成,不需要在申请O(N)的空间~。


102. binary tree level order traversal

二叉树的按层次遍历

一般树的问题都可以递归的去做,代码如下,自己看看就懂了。

1.递归

/**

 * Definition for a binary tree node.

 * struct TreeNode {

 *     int val;

 *     TreeNode *left;

 *     TreeNode *right;

 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}

 * };

 */

class Solution {

public:

     void printbyOrder(TreeNode*root,int x,vector<int> &avector){

        if (root==NULL) return;

        else{

            if (x==1) {  avector.push_back(root->val);}

            else{

                printbyOrder(root->left,x-1,avector);

                printbyOrder(root->right,x-1,avector);

            }

        }

    }

    vector<vector<int>> levelOrder(TreeNode* root) {

        vector<vector<int>> result;

        for(int i=1;;i++){

            vector<int> avector;

            printbyOrder(root,i,avector);

            if (avector.size()==0) break;

            else{

                result.push_back(avector);

            }

        }

        return result;

}

2.

用队列实现(为啥是c++???没错我就是喜欢在java c++ python随机挑个语言来写)

int i = 0;

 while (!Q.empty()) {

 i++; 

int k = Q.size();

 for (int j=0; j<k; j++)

 { TreeNode* rt = Q.front();

 if (rt->left) Q.push(rt->left); 

 if (rt->right) Q.push(rt->right);

 Q.pop(); 

if (rt->left==NULL && rt->right==NULL) return i; } //i为层次

 }


9. Palindrome Number

题意为判断一个数字是否为回文数字,注意,将一个大的回文数首尾倒置可能会出现溢出的情况,该怎样处理这种问题呢?

1.我们最先想到用一个long来储存回文数,但显然这个方法有局限性,如果要处理的数字是long型?我们是否还能继续使其不溢出?

2.只判断一半,这个经过简单思考后也可以想出,大致代码如下。

public: bool isPalindrome(int x) 

{ if(x<0|| (x!=0 &&x%10==0)) return false; 

int sum=0; while(x>sum) //加个判断条件,只比较前半段和后半段

{ sum = sum*10+x%10; x = x/10; }

 return (x==sum)||(x==sum/10); } };//奇数位或者偶数位

3.讨论区看到一个思路:

溢出发生在sum = sum*10+x%10;

如果我们记录变化之前的sum值,然后把变化后的(sum-x%10)/10和之前的sum值比较,若不相等,则肯定溢出了。这个方法有一定的局限性,而且正确性也存疑,是否存在一个数他溢出后的值-x%10再除以10正好和原数相等?似乎不太好证明,如果你有兴趣可以自己探究下。


160.Intersection of Two Linked Lists


题意:求两个链表的交点


1.最垃圾的:俩链表双重循环找第一个相等的,O(N^2)

2.思考这种有交点链表特性:他们尾部都相同,头部一个比一个"长一点",我们可以计算出俩链表长度,设置俩游标在表头,然后预处理,将长链表的游标从首个前移动俩长度之差个节点,这样如果有交点,一定会移动到某处相等。代码如下:

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA==null || headB==null) return null;
        else{
            int anum=0,bnum=0;
            ListNode h=headA;
            while(h!=null){
                h=h.next;
                anum++;
            }
            h=headB;
            while(h!=null){
                h=h.next;
                bnum++;
            }
            int x=Math.abs(anum-bnum);
            if (anum>=bnum){
                ListNode p=headA;
                ListNode q=headB;
                for (int i=0;i<x;i++){
                    p=p.next;
                }
                while (p!=null&&q!=null){
                    if (p.equals(q)) return p;
                    p=p.next;
                    q=q.next;              
                }
                return null;
            }
            else{
                ListNode p=headA;
                ListNode q=headB;
                for (int i=0;i<x;i++){
                    q=q.next;
                }
                while (p!=null&&q!=null){
                    if (p.equals(q)) return p;
                    p=p.next;
                    q=q.next;
                    
                }
                return null;
            }
            
        }
    }
}

3.Discuss一个brilliant的解法:因为两个链表的和长度一定相等,所以把两个链表都从头开始,每次移动一个节点,移动到null就转为下一个链表的头,这样如果存在交点,一定会在某时相等。酷不酷?~~~~~~~~~~~~~·


88. Merge Sorted Array

设想在方法中新建个数组三,把排好序的放到数组三,再nums1=nums3?

行不通,java中是传引用,如果nums1[]实际是在栈中的一个地址,所以类似改变地址nums1=nums3的操作不能对原数组产生影响,但是改变数组内的值可以。

于是我们只能就地排序,(在nums1中),思考后发现只有倒序才有可能实现,正序会覆盖未排序的内容。很巧妙吧~

Like this


public class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
      int k=m+n-1;
      m--;
      n--;
        
         while(m>=0 && n>=0){
         if(nums1[m]>nums2[n]){
             nums1[k--]=nums1[m--];
         }
         else{
             nums1[k--]=nums2[n--];
         }
         }
        while(n>=0){
            nums1[k--]=nums2[n--];
        }
      }   
}


36. Valid Sudoku

题意:判断是否为个数独合法状态

自己写的代码有点丑,学习下mostvotes中简洁的代码把。

c++

sValidSudoku(vector<vector<char> > &board) 

{ int used1[9][9] = {0}, used2[9][9] = {0}, used3[9][9] = {0}; 

for(int i = 0; i < board.size(); ++ i)

   for(int j = 0; j < board[i].size(); ++ j) 

if(board[i][j] != '.'

{jaint num = board[i][j] - '0' - 1,  k = i / 3 * 3 + j / 3;  //k未第几个小块

if(used1[i][num] || used2[j][num] || used3[k][num]) 

return false; 

used1[i][num] = used2[j][num] = used3[k][num] = 1

return true; //遍历完无重复

}

java hashset

public boolean isValidSudoku(char[][] board) 

{ for(int i = 0; i<9; i++)

{

 HashSet<Character> rows = new HashSet<Character>(); 

HashSet<Character> columns = new HashSet<Character>();

 HashSet<Character> cube = new HashSet<Character>(); 

for (int j = 0; j < 9;j++)

//Hashset.add成功加入返回1,若已有元素返回0

if(board[i][j]!='.' && !rows.add(board[i][j])) return false;

  if(board[j][i]!='.' && !columns.add(board[j][i])) return false; 

int RowIndex = 3*(i/3); int ColIndex = 3*(i%3); 

if(board[RowIndex + j/3][ColIndex + j%3]!='.' && !cube.add(board[RowIndex + j/3][ColIndex + j%3])) return false; 

return true; 

}


190. Reverse Bits

题意:反转一个数的二进制数

评论区一个天才的做法,供大家欣赏下

一个时间复杂度为Ologsizeofn)))的算法,采用了分治的方法

class Solution 

{ public: uint32_t reverseBits(uint32_t n) 

{ n = (n >> 16) | (n << 16); 

n = ((n & 0xff00ff00) >> 8) | ((n & 0x00ff00ff) << 8); 

n = ((n & 0xf0f0f0f0) >> 4) | ((n & 0x0f0f0f0f) << 4); 

n = ((n & 0xcccccccc) >> 2) | ((n & 0x33333333) << 2); 

n = ((n & 0xaaaaaaaa) >> 1) | ((n & 0x55555555) << 1); 

return n; } };

eg.8位的,类似这样 abcdefgh -> efghabcd -> ghefcdab -> hgfedcba


219. Contains Duplicate II

Given an array of integers and an integer k, find out whether there are two distinct indices i and j in the array such that nums[i] = nums[j] and the difference between i and jis at most k.

My solution

用hashmap,如果便利过程中发现有重复的元素,检查map中value保存的index与当前差值是否小于k。

public class Solution {

    public boolean containsNearbyDuplicate(int[] nums, int k) {

        HashMap<Integer,Integer> a=new HashMap<Integer,Integer>(1+k);

        for (int i=0;i<nums.length;i++){

            if (a.get(nums[i])!=null){

                if ((i-a.get(nums[i]))<=k)

                    return true;

                else{

                    a.put(nums[i],i);

                }

            }

            else{

                a.put(nums[i],i);

            }

        }

        return false;

    }

}

Most votes solution

用hashset,手动维持一个大小为k的窗口

public boolean containsNearbyDuplicate(int[] nums, int k)

 { Set<Integer> set = new HashSet<Integer>(); 

for(int i = 0; i < nums.length; i++)

{

 if(i > k) set.remove(nums[i-k-1]) //大于k需要每次移除一个set中的值

if(!set.add(nums[i])) return true; }

return false;

 }

Fastest soluton?

先快速排序,然后判断,综合效率最快,处理数字序列问题时一定要想到排序~

https://leetcode.com/discuss/89129/5ms-98-8%25-java-solution



58. Length of Last Word

Mostvotes

简洁并且不调用其他函数的solution

int lengthOfLastWord(const char* s) { 

int len = 0;

  while (*s)  { 

if (*s++ != ' ') 

++len; 

else if (*s && *s != ' ')

  len = 0;

 }

  return len; 

}

len储存当前单词的长度,每次遇到一个新空格且没到字符串结尾就重置len,最后得到的就是最后单词的长度。

203. Remove Linked List Elements

题意:删掉单链表中所有的值为val的元素

1.Mostvotes

递归

public ListNode removeElements(ListNode head, int val) 

if (head == null)

  return null; 

head.next = removeElements(head.next, val);

  return head.val == val ? head.next : head; 

}

2.Mysoluton

即增加个虚拟链表头,此方法也适用其他边界处理较麻烦的问题!更简单些


public class Solution {

    public ListNode removeElements(ListNode head, int val) {

        ListNode hhead=new ListNode(0);

        hhead.next=head;

        ListNode pre=hhead;

        ListNode now=head;

        while(now!=null){

            if (now.val==val){

                pre.next=now.next;

                now=now.next;

            }

            else{

                pre=pre.next;

                now=now.next;

            }

            }

            return hhead.next;

}


14. Longest Common Prefix


题意:求一堆字符串最长前缀

  Most votes的答案看起来效率并没有我的高,所以不贴了,还有一种做法先排序,然后比较第一个与最后一个,效率偏低。正常比较的复杂度应该是O(N+M)(M为第一个字符串长度)

public class Solution {

    public String longestCommonPrefix(String[] strs) {

        String result="";

        int prefixnum=0;

        if (strs.length==0) return result;

        else{

            result=strs[0];

            prefixnum=result.length();

            for(int i=1;i<strs.length;i++){

                int j;

                for(j=Math.min(prefixnum,strs[i].length());j>0;j--){

                    //如果前j字母相等,break

                    if (result.substring(0,j).equals(strs[i].substring(0,j))){

                        break;

                    }

                }

                prefixnum=j;

                if (j==0) return "";

                result=strs[i].substring(0,j);

            }

            return result;

        }

    }

}


257. Binary Tree Paths

1.传统递归做法:

public class Solution {

    List<String> result;

    public List<String> binaryTreePaths(TreeNode root) {

        result=new ArrayList<String>();

        if (root==null) return result;

        else{

        dfs(root,root.val+"");

        return result;

        }

    }

    public void dfs(TreeNode node,String s){

        if (node==null) return;

        else{

            if (node.left==null && node.right==null) {

                result.add(s);

                return;

                

            }

            if (node.left!=null) dfs(node.left,s+"->"+node.left.val);

            if (node.right!=null) dfs(node.right,s+"->"+node.right.val);

        }

    }

    

}

2.还可以用·栈来模拟dfs,用队列模拟bfs,相关python代码:

def binaryTreePaths1(self, root):

    if not root:

        return []

    res, stack = [], [(root, "")]

    while stack:

        node, ls = stack.pop()

        if not node.left and not node.right:

            res.append(ls+str(node.val))

        if node.right:

            stack.append((node.right, ls+str(node.val)+"->"))

        if node.left:

            stack.append((node.left, ls+str(node.val)+"->"))

    return res

 

# bfs + queue

def binaryTreePaths2(self, root):

    if not root:

        return []

    res, queue = [], collections.deque([(root, "")])

    while queue:

        node, ls = queue.popleft()

        if not node.left and not node.right:

            res.append(ls+str(node.val))

        if node.left:

            queue.append((node.left, ls+str(node.val)+"->"))

        if node.right:

            queue.append((node.right, ls+str(node.val)+"->"))

return res

 

234. Palindrome Linked List

题意判断一个单链表是否回文,两个方法一个用快指针(一步前进两个),和慢指针找到链表的中点,然后把后半链表就地逆序,与前半部分相比较。

另一种按我的思路整个逆序一定要再新申请空间!否则原链表结构都被破坏,无法比较!


28. Implement strStr()

1.普通暴力搜索:

特别注意边界情况,当要查询的字符串为空时,返回0而不是-1;

   for(int i=0;i<haystack.length();i++)

            for(int j=0;j<needle.length();j++){

                if (i+j>haystack.length()-1) return -1; //注意此句在比较是否相等前面

                if (haystack.charAt(i+j)!=needle.charAt(j)) break;

                if (j==needle.length()-1) return i;

            }

        return -1; //有可能主字符串为空

2.Kmp算法

Next 求法:仿照kmp算法,模式串和主串为同一个串,就是在key串中匹配他的前缀,注意初始化,i=1,j=0;匹配的过程中求下一个next[i+1]的值,如果next[1]到next[n] next[1]初始化为0,0为边界条件,用于判断。注意上段说的都是next[1]~next[n],需要加个前缀字符,否则next[0]可初始化为-1;

public class Solution {

    public int strStr(String haystack, String needle) {

        if (needle.length()==0) return 0;

        if (needle.length()>haystack.length()) return -1;

        int n=needle.length();

        int[] next=new int[n+2];

        int i=1;int j=0;

        next[1]=0; 

        haystack="0"+haystack;

        needle="0"+needle;

        

        while(i<needle.length()-1){

            if (needle.charAt(i)==needle.charAt(j)||j==0){

                ++i;

                ++j;

                next[i]=j;

            }

            else{

                j=next[j];

            }

        }

       

        i=1;

        j=1;

        while(i<=haystack.length()-1&&j<=needle.length()-1){

                if (haystack.charAt(i)==needle.charAt(j)||j==0){

                    i++;

                    j++;

                }

                else{

                    j=next[j];

                }

                

                

            }

            if (j>needle.length()-1) return(i-j);

            else return -1;

        }

}

6. ZigZag Conversion

刷题心得,任何情况下都要考虑数组下标在某种情况下能否越界,尤其是边界情况!

1.MYsolution

一行一行地加入,即算出没行的两次间隔,从主串中提取他们。

public class Solution {

    public String convert(String s, int numRows) {

        String[] result=new String[numRows];

        for(int i=0;i<numRows;i++) result[i]="";

        if (numRows==1) return s;

            for(int j=0;j<numRows;j++){

                int interval1=2*numRows-2*(j+1);

                int interval2=(2*numRows-2)-interval1;

                int start=j;

                for(int i=0;;i++){

                    if(i%2==0) {

                        if (start>=s.length()) break;

                        if (interval1!=0){

                        result[j]=result[j]+s.charAt(start)+"";

                        start=start+interval1;

                        }

                    }

                    else{

                        if (start>=s.length()) break;

                        if (interval2!=0){

                        result[j]=result[j]+s.charAt(start)+"";

                        start=start+interval2;

                        }

                    }

                }

        }

        String sb="";

        for(int j=0;j<numRows;j++){

            sb=sb+result[j];

        }

        return sb;

}

}

2.Mostvotes

z字形加入,先从上到下,再从下到上...

List<String> list=new ArrayList();

    if(nums.length==1){

        list.add(nums[0]+"");

        return list;

    }

    for(int i=0;i<nums.length;i++){

        int a=nums[i];

        while(i+1<nums.length&&(nums[i+1]-nums[i])==1){

            i++;

        }

        if(a!=nums[i]){

            list.add(a+"->"+nums[i]);

        }else{

            list.add(a+"");

        }

    }

return list;

 

278. First Bad Version


二分法(head+tail/2注意会不会溢出!!!!!!!!1


// 这样写二分更好,这样最后start=end=bad

public int firstBadVersion(int n) {

    int start = 1, end = n;

    while (start < end) {

        int mid = start + (end-start) / 2;

        if (!isBadVersion(mid)) start = mid + 1;

        else end = mid;            

    }        

    return start;

}


1.TWO SUM

为了避免搜到自身,可以先搜targert-n(i),然后再加入hashmap,若存在答案,肯定能搜到


168. Excel Sheet Column Title

频繁操作字符串时,请用stringbuffer或者stringbuilder,不同之处,StringBuffer 是线程安全的,而 StringBuilder 则没有实现线程安全功能,所以性能略高

 

StringBuilder str=new StringBuilder("");

str.append("jaewkjldfxmopzdm");

str.insert(i,",");

 

189. Rotate Array

java中array的方法:

从Array中创建ArrayList

String[] stringArray = { "a", "b", "c", "d", "e" };

ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(stringArray));

System.out.println(arrayList);

// [a, b, c, d, e]

连接两个数组

int[] intArray = { 1, 2, 3, 4, 5 };

int[] intArray2 = { 6, 7, 8, 9, 10 };

// Apache Commons Lang library

int[] combinedIntArray = ArrayUtils.addAll(intArray, intArray2);

数组翻转

int[] intArray = { 1, 2, 3, 4, 5 };

ArrayUtils.reverse(intArray);

System.out.println(Arrays.toString(intArray));

//[5, 4, 3, 2, 1]

依然用到了万能的ArrayUtils。

从数组中移除一个元素

int[] intArray = { 1, 2, 3, 4, 5 };

int[] removed = ArrayUtils.removeElement(intArray, 3);//create a new array

System.out.println(Arrays.toString(removed));

使用java数组要注意

思考这俩段代码为什么错误了:

public class Solution {

    public void rotate(int[] nums, int k) {

        int[] temp=new int[nums.length];

        temp=nums; //这行只是传引用,也就是nums那段实际地址,既叫temp,又叫nums,你在修改nums数组值时,temp也会改变,循环出错,所以你要想拷贝一段一个相同数组请用for或者int copy[]=Arrays.copyof(a,a.length)方法,错误很隐蔽....

        k=k%nums.length;

        for(int i=0;i<nums.length;i++){

            nums[(i+k)%nums.length]=temp[i]; //

        }

    }

}

 

public class Solution {

    public void rotate(int[] nums, int k) {

        int[] result=new int[nums.length];

        k=k%nums.length;

        for(int i=0;i<nums.length;i++){

            result[(i+k)%nums.length]=nums[i];

        }

       nums=result; //java是传引用,出了这个方法后,num值并不会被改变。

    }

}


165. Compare Version Numbers

注意java中Split中字符串为正则表达式,如果要匹配单引号双引号 用一个 \ 转义

如果要匹配点,需要用两个\\转义,首先字符串中的\\被编译器解释为\
然后作为正则表达式,\.又被正则表达式引擎解释为.

如果在字符串里只写\.的话,第一步就被直接解释为.,之后作为正则表达式被解释时就变成匹配任意字符了


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值