一道leetcode题引发的java数据结构

前些天在同学的内推下,获取了华为的线上面试邮件,对于一个干过接近3年的外包员工收到这种正式邀请还是有点激动的,但是因为知道是做题,自己上一次刷leetcode都不知道是什么时候了,所以心里也没底,就随便在华为面试那个平台刷了几道题,结果可想而知,最后没有通过。

于是乎想这几天重新刷刷leetcode,发现改了中文名字叫 力扣 (太丑了),然后就去刷第一道题:

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

听起来就很简单,上来就干:

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] result =null;
        for(int i = 0; i < nums.length; ++i) {
            int j = i + 1;
            for(; j < nums.length; ++j) {
                if(nums[i] + nums[j] == target)
                    result =  new int[] {i, j};
            }
        }
        return result;
    }
}

但是这么一来,两个for循环,时间复杂度达到了O(n)^2,应该不对,直接查看解答,发现一个巧妙的用法,用到了HashMap数据结构,答案如下:

class Solution implements Serializable{
    private static int[] twoSum(int[] nums, int target) {
        HashMap map = new HashMap<>();
        for (int i = 0; i < nums.length; ++i) {
            int complement = target - nums[i];
            if (map.containsKey(complement) && map.get(complement) != i)
                return new int[]{i, complement};
            map.put(nums[i], i);
        }
        throw new IllegalArgumentException("no result");
    }
}

HashMap查找key的方法是常数时间,所以时间复杂度为O(n)就解决了这个问题,看起来很不错,但是仔细想:为什么HashMap查找key的时间复杂度为常数呢,然后就去寻找答案。

HashMap

在源码中发现两个值 static final int TREEIFY_THRESHOLD = 8; static final int UNTREEIFY_THRESHOLD = 6; 根据源码注释初步判断,默认情况下,当hashmap的节点数目少于8的时候,使用的是list结构来存储,大于8的时候使用的是tree结构存储,并且这个数是红黑树(为什么是红黑树,应该是兼顾查询和插入的时间),并且在HashMap的源码中找到了两个static的class定义:

  • static class Node implements Map.Entry
  • static final class TreeNode extends LinkedHashMap.Entry
    第一个就是当HashMap数据较少,存储为list的时候实际使用的结构类,继承了Map.Entry的接口,属性中只有K、V、next,是一个明显的链式结构;第二个是当HashMap数据较大时候使用的结构,包含
        TreeNode parent;  // red-black tree links
        TreeNode left;
        TreeNode right;
        TreeNode prev; 

这些变量说明了它的二叉树结构。
综上,结论是当我们的数组少于8的时候,HashMap还是是链表结构,从里面发现key的时间复杂度是O(n),并没有优化算法,但是当大于8的时候使用了红黑树之后,时间复杂度就有了明细的优势。


仔细想想,数组不是有一个工具类java.util.Arrays吗,我记得这个工具类,提供了数组的一些常用的方法,排序和搜索,从里面找到搜索算法binarySearch

Arrays.binarySearch

源码中的注释如下:

/* Searches the specified array of longs for the specified value using the
* binary search algorithm. The array must be sorted (as
* by the {@link #sort(long[])} method) prior to making this call. If it
* is not sorted, the results are undefined. If the array contains
* multiple elements with the specified value, there is no guarantee which
* one will be found.

这是一个使用二分查找搜索数据的算法,使用之前,数组必须经过sort排序。不符合我们的预期。

你可能感兴趣的:(一道leetcode题引发的java数据结构)