zoukankan      html  css  js  c++  java
  • leetCode没那么难啦 in Java (一)

    前言

       感觉写博客是一个很耗心力的东西T_T,简单的写了似乎没什么用,复杂的三言两语也只能讲个大概,呸呸...怎么能有这些消极思想呢QAQ!那想来想去,先开一个leetcode的坑,虽然已经工作了,但是每天拿一两道题打发打发也不错嘛,不仅能锻炼思维,还能复习一些算法思想,又不怎么耗费时间撰写...还能骗博客数...,额好像又说了啥内心的真实想法:)...

    Go

    两数相加 Two Sum

    • Given an array of integers, return indices of the two numbers such that they add up to a specific target.
      You may assume that each input would have exactly one solution.
      Example:
      Given nums = [2, 7, 11, 15], target = 9,
      Because nums[0] + nums[1] = 2 + 7 = 9,
      return [0, 1].

    • 翻译: 两数之和
      给定一个整形数组和一个整数target,返回2个元素的下标,它们满足相加的和为target。
      你可以假定每个输入,都会恰好有一个满足条件的返回结果,也就是多种答案的情况不予考虑
      例如给定了数组 nums = [2, 7, 11, 15], 需要的target = 9,
      因为 nums[0] + nums[1] = 2 + 7 = 9,
      所以返回 [0, 1]


    • 思路一
      暴力解法,好吧程序员做久了人有时候容易变傻,就好像现在让你求从1加到100的和你想都不想for循环100次还说这是复杂度为O(n)哦,殊不知几百年前还在读小学的高斯就用求和公式O(1)时间就解决了T_T
      废话说完了,既然暴力解法这么傻,为啥还要讲,因为很多题目实在想不到解法时,可以先拟定一个暴力解法,然后再在这上面去优化时间与空间,寻找思路。
      最简单暴力解决就是多次遍历,两轮循环,把他们的和加起来,等于target就返回下标,如果啥都没就返回[-1,-1]
        public int[] twoSum01(int[] arr, int target) {
    
            if (arr == null) return new int[]{-1, -1};
    
            for (int i = 0; i < arr.length - 1; i++) {
                for (int j = i + 1; j < arr.length; j++) {
                    if (arr[i] + arr[j] == target) return new int[]{i, j};
                }
            }
    
            return new int[]{-1, -1};
        }
    

    核心代码就是中间的三行,很简单的两次遍历,数据量如果是在(10^4)这个范围内,(O(n^2))级别的算法的时间在1秒内左右,所以如果数据量不是很大,这种暴力解法也是可以接受的。

    • 思路二
      (O(n^2))的时间复杂度如果数据量很大自然是不能接受的,这里就从上面的暴力算法改进,在思路一中,每次遍历元素的时候都要把他和剩下的所有元素都比一遍,这真是太蠢了,你给一个小朋友做这道题他都不会这么解,那小朋友怎么解呢?
      假设数组内容是[2,7,11,15],目标值是17,那小朋友会先看2,17-2=15,那他就会去找有没有15,有15就把他们的位置给记下来,没有15就再看下一个数字。这里我们再把这种想法优化一下,程序化一下,代码如下
        public int[] twoSum(int[] nums, int target) {
            if (nums == null) return new int[]{-1, -1};
            Map<Integer, Integer> map = new HashMap<>();// 答案MAP,用于存储答案,key为数字,value为在数字集合中下标位置
    
            for (int i = 0; i < nums.length; i++) {
                Integer exceptNum = target - nums[i];//期望的答案
                if (map.containsKey(exceptNum)) return new int[]{map.get(exceptNum), i}; //如果寻找到答案了,直接返回
                else map.put(nums[i], i); //如果没有找到对应的答案,那么就把这个数本身作为答案放入答案map,根据a+b=b+a,正在遍历的数即是请求也是答案
            }
            return new int[]{-1, -1};
        }
    

    这里最初的思路就是拿空间换时间,最简单的处理是把所有的数组里的数都放到哈希表中,然后直接遍历get就可以了,但是这样未免太浪费空间,所以引入第二步优化思路,我需要多少,我就存多少元素,利用加法交换律a + b = b + a,正在遍历的元素同时就成为了备选答案存入map,这样比单纯的存入map中时间与空间的消耗期望值都是会少一些的。

    总结

      题目很简单,算法题也有很多,但是思路其实并没有那么繁杂,合理利用这些思路,理解了一道题,这一类的题目就都理解了。

    • 在没有头绪的时候先尝试暴力解法,然后看看暴力解法里哪一步是可以优化的,例如本题中最外层循环肯定是不可避免的,但是内循环对于每一个数字都遍历所有就很没有必要,就可以在这点上作优化
    • 空间换时间,哈希表往往是最常用的选择之一,当然不仅仅是哈希表,树,堆,图,都是值得考虑的对象
    • 在使用空间换时间的优化中,充分利用已知的元素,最好能将已经遍历的过的元素存储再利用,这样往往能降低不少空间使用与时间消耗,虽然都是O(N)级别的空间,但是前面的常数系数明显是要小的。
  • 相关阅读:
    【leetcode】1020. Partition Array Into Three Parts With Equal Sum
    【leetcode】572. Subtree of Another Tree
    【leetcode】123. Best Time to Buy and Sell Stock III
    【leetcode】309. Best Time to Buy and Sell Stock with Cooldown
    【leetcode】714. Best Time to Buy and Sell Stock with Transaction Fee
    【leetcode】467. Unique Substrings in Wraparound String
    【leetcode】823. Binary Trees With Factors
    【leetcode】143. Reorder List
    【leetcode】1014. Capacity To Ship Packages Within D Days
    【leetcode】1013. Pairs of Songs With Total Durations Divisible by 60
  • 原文地址:https://www.cnblogs.com/invoker-/p/7615981.html
Copyright © 2011-2022 走看看