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)级别的空间,但是前面的常数系数明显是要小的。
  • 相关阅读:
    我理解的Node.js
    How to handle the issue of node.js msi to roll back under windows 8
    转:.Net 中AxShockwaveFlash的解析
    鱼哥的C++学习笔记(一)编译方法
    TabControl样式编写
    Cocos2d on VS12 step by step
    C# 控制Windows系统音量
    系统环境换成Win8+Vs2012碰到的问题记录
    Http学习笔记(一)
    WPF ListBox Template解析
  • 原文地址:https://www.cnblogs.com/invoker-/p/7615981.html
Copyright © 2011-2022 走看看