当前位置 博文首页 > 宋者为王:【算法】数据结构与算法基础总览(中)——刷Leetcode

    宋者为王:【算法】数据结构与算法基础总览(中)——刷Leetcode

    作者:宋者为王 时间:2021-02-07 14:24

            最近重新学习数据结构与算法以及刷leetcode算法题时,发现不少jdk自带的方法可以提升刷题的效率。这些小技巧不仅仅对刷算法题带来便利,对我们平时开发也是很有帮助的。本文以java语言为基础,记录了目前已经使用或看到过的一些小技巧,后续在刷题过程中,还会持续更新。

     

    一、数组

      1、使用Arrays.sort(int[] a)进行排序

          底层采用的是快速排序算法实现的:时间复杂度为O(nlogn),空间复杂度O(logn),不稳定。默认是从小到大排序。

    int[] arr = new int[]{2, 9, 6, 8, 4, 3};
    Arrays.sort(arr);
    System.out.println(Arrays.toString(arr));

    打印结果:

    [2, 3, 4, 6, 8, 9]

    参数可以是其它基本数据类型,也可以是自定义类型,可以通过使用Comparator比较器来自定义排序顺序。

    例如,降序排列:

    1 Integer[] arr = new Integer[]{2, 9, 6, 8, 4, 3};
    2 Arrays.sort(arr, new Comparator<Integer>() {
    3     @Override
    4     public int compare(Integer t0, Integer t1) {
    5         return t1 - t0;
    6     }
    7 });
    8 System.out.println(Arrays.toString(arr));

    打印结果:

    [9, 8, 6, 4, 3, 2]

      2、使用Arrays.toString(int[] arr)将数组组合成字符串

         内部是通过StringBuilder + for 循环来实现的,该方法可以方便调试查看数组的值,而无需自己手动来组装字符串。

    int[] arr = new int[]{2, 9, 6, 8, 4, 3};
    System.out.println(Arrays.toString(arr));

    打印结果:

    [2, 9, 6, 8, 4, 3]

    同样,该方法的参数数组类型可以是其它数据类型。

      3、使用Arrays.fill()一次性给数组填充指定值

           有时候我们需要将数组中的所有元素都初始化填充为指定值,一般的做法是通过循环来一一赋值,这样做显然不够简洁。所幸,java sdk中提供了简洁的方法来一步实现,如下所示:

    int[] arr = new int[10];
    Arrays.fill(arr,1);
    System.out.println(Arrays.toString(arr));

    打印结果:

    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

    实际上fill()内部实现也是通过for循环一一赋值的,但对开发者使用而言,确实简洁了很多。

     

    二、ArrayList

      1、使用构造函数或者addAll将一个集合中的内容添加到新的ArrayList中

    //构造函数
    public ArrayList(Collection<? extends E> c) 
    //addAll方法
    public boolean addAll(Collection<? extends E> c) 

    内部实现原理:ArrayList内部维护了一个数组,无论是使用构造函数还是addAll方法,都是将给定集合中的元素复制到该数组中。

    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    List<Integer> newList1 = new ArrayList<>(list);
    System.out.println(newList1);
    List<Integer> newList2 = new ArrayList<Integer>();
    newList2.addAll(list);
    System.out.println(newList2);

    打印结果:

    [1, 2, 3]
    [1, 2, 3]

      2、ArrayList与数组互相转化

        (1)使用list.toArray()将ArrayList转为数组

    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    Object[] a = list.toArray();
    System.out.println(Arrays.toString(a));

    打印结果:

    [1, 2, 3]

        (2)使用Arrays.asList(数组) 将数组转为ArrayList

    Integer[] arr = new Integer[]{2, 9, 6, 8, 4, 3};
    List<Integer> arrList = Arrays.asList(arr);
    System.out.println("size=" + arrList.size() + ";arrList=" + arrList);

    打印结果:

    size=6;arrList=[2, 9, 6, 8, 4, 3]

      3、使用Collections.reverse(list) 倒转ArrayList中的元素

    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    Collections.reverse(list);
    System.out.println(list);

    打印结果:

    [3, 2, 1]

      4、使用Set来过滤具有相同元素的list

    Set<List<String>> set = new HashSet<>();
    List<String> list1 = Arrays.asList("a", "b");
    List<String> list2 = Arrays.asList("a", "b");
    set.add(list1);
    set.add(list2);
    System.out.println(list1 == list2);
    System.out.println(set);

    打印结果:

    false
    [[a, b]]

    从打印结果可知,list1和list2不是同一个对象,但其中包含的元素一样(内容和顺序都一样),Set就只会保存第一个加入的list。目前只发现set中添加的List对象时有这个特性,如果使用数组,或者StringBuilder等引用型对象就不生效,且如果两个list中元素顺序不一致,也不会有过滤效果。

     

    三、HashMap

        1、在new HashMap对象时,初始化其中的内容

    public Map<String, String> map = new HashMap() {
            {
                put("k1", "v1");
                put("k2", "v2");
            }
        };
    
    System.out.println(map);

    打印结果:

    {k1=v1, k2=v2}

    使用该方法后,就不用专门在某个方法中通过put来添加内容,无疑,在很多场景下可以带来不少便利。

        2、类似于ArrayList类,HashMap也可以通过构造函数或者putAll()方法,一次将已知的hashMap内容添加进来:

    //方式一(map为上一节中的对象):
    Map<String,String> newMap = new HashMap(map);
    //方式二:
    Map<String,String> newMap = new HashMap();
    newMap.putAll(map);
    
    System.out.println(newMap);

    打印结果:

    {k1=v1, k2=v2}

     

    四、字符串

      1、按照多个空格,对字符串进行分割:split(“\\s+”)或者split(" +")

        例如:

    String s = "leetcode    is     very     good!";
    String[] arr = s.split("\\s+"); //或者s.split(" +");
    System.out.println(Arrays.toString(arr));

    打印结果:

    [leetcode, is, very, good!]

      2、去掉字符串首尾空字符串:trim()

    1 String s = "  ab cd   ";
    2 Sytem.out.println(s.trim());

    打印结果:

    ab cd

      3、拼接字符串:join()

    1 String[] strArray = {"ab","cd","ef"};
    2 System.out.println(String.join(" ",strArray));

    打印结果:

    ab cd ef

    这里将数组组合成字符串,用“ ”连接。join的第一个参数可以替换其它的连接符号,第二个参数除了使用数组外,还可以使用LIst,Deque等集合对象

     

     五、位运算

           机器世界计算和存储最终使用的数据格式都是二进制,采用位运算可以更加贴近机器语言,提高计算效率(当今计算机新能如此强的情况下,一些小范围使用位运算提升的效率看起来肯定是微乎其微,不过使用位运算逼格肯定提升一个档次~~)。

      1、判断奇偶

          以往判断奇偶采用的都是 x % 2 == 1 和 x % 2 == 0 ,这里我们可以使用&运算来判断:

    (x & 1) == 1 // 说明x为奇数
    (x & 1) == 0 // 说明x为偶数

    例如:

    System.out.println("5是奇数吗?:" + ((5 & 1) == 1));
    System.out.println("5是偶数吗?:" + ((5 & 1) == 0));
    System.out.println("4是奇数吗?:" + ((4 & 1) == 1));
    System.out.println("4是偶数吗?:" + ((4 & 1) == 0));

    打印结果:

    5是奇数吗?:true
    5是偶数吗?:false
    4是奇数吗?:false
    4是偶数吗?:true

      2、除以2

           以往一个数x除以2的计算方式是x / 2,这里采用位运算的方式为:

    x >> 1;//右移1位,表示除以2
    x << 1;//左移1位,表示乘以2

    例如:

    System.out.println(5 >> 1);
    System.out.println(5 << 1);

    打印结果为:

    2
    10   

    (持续完善中......)

    bk