数据结构是编程里面非常重要的一环,我们需要用很大的精力去学习它。

数据结构

数组

数组指一组数据的集合,数组中的每个数据被称作元素。

数组的优点:

  1. 构建一个数组十分简单
  2. 能让我们在O(1)的时间里根据数组的下标(index)查询某个元素

数组的缺点:

  1. 构建的时候必须分配一段连续的空间
  2. 查询某个元素是否存在的时候必须遍历整个数组,耗费O(n)的时间(n为元素的个数)
  3. 删除或者添加某个元素的时候同样需要耗费O(n)的时间

例题

给定两个字符串 st ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例:
输入: s = "anagram", t = "nagaram"
输出: true
说明:
你可以假设字符串只包含小写字母。

// 这里我们提供两个解题思路
// 方法一,对两个字符串中的元素进行个数计算,第一个进行加操作,第二个进行减操作,最后对比元素是否有剩余即可
public boolean isAnagram(String s, String t) {
    if (s.length() != t.length()) {
        return false;
    }
    Map<String, Integer> map = new HashMap<>();
    String[] a = s.split("");
    String[] b = t.split("");
    for (String c : a) {
        int num = map.get(c) == null ? 0 : map.get(c);
        map.put(c, num + 1);
    }
    for (String d : b) {
        int num = map.get(d) == null ? 0 : map.get(d);
        if (num > 0) {
            map.put(d, num - 1);
        } else {
            return false;
        }
    }
    for (int e : map.values()) {
        if (e > 0) {
            return false;
        }
    }
    return true;
}

// 方法二,对数组进行排序,如果字符串所含字母相同的话,排序后的数组肯定相同
public boolean isAnagram(String s, String t) {
    if (s.length() != t.length()) {
        return false;
    }    
    String[] a = s.split("");
    Arrays.sort(a);
    String[] b = t.split("");
    Arrays.sort(b);
    return Arrays.equals(a, b);
}

链表

单链表:

链表中的每个元素实际上是一个单独的对象,而所有对象都通过每个元素中的引用字段连接在一起。

图片.png

双链表:

与单链表不同的是,双链表的每个结点中都含有两个引用字段。

图片.png

链表的优点:

  1. 灵活地分配内存空间。
  2. 能在O(1)时间内删除或者添加元素。

链表的缺点:

  1. 查询元素需要O(n)的时间

例题

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

特点

后进先出

例题

根据每日 气温 列表,请重新生成一个列表,对应位置的输出是需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。

public static int[] dailyTemperatures(int[] T) {
    // 这里需要用到栈,将温度的下标依次的放入到栈中,如果遇到比之前高的温度就可以根据下标计算时间
    Stack<Integer> stack = new Stack<>(0);
    // 新建一个长度和T一致的空数组
    int[] a = new int[T.length];
    // 遍历T
    for (int i = 0; i < T.length; i++) {
        // 循环栈
        while (!stack.empty()){
            // 判断栈最上层的下标对应的值和T此时的值的大小
            if(T[i] > T[stack.peek()]){
                // 如果T此时的值大就说明找到了超过栈最上层下标对应的值的数据,通过下标相减获取天数
                a[stack.peek()] = i - stack.peek();
                // 弹出栈最上层的下标
                stack.pop();
            } else {
                // 没有超过就退出此次循环
                break;
            }
        }
        // 将下标依次放入到栈中
        stack.push(i);
    }
    return a;
}

队列

特点

先进先出

/**
     * 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
     * 返回滑动窗口中的最大值。
     *
     * @param nums
     * @param k
     * @return
     */
    public int[] maxSlidingWindow(int[] nums, int k) {
        // 这里我们可以想我们每次拿出给定数组中的k个元素组成一个新的数组,对新数组排序后取最大值即可
        int[] newInt = new int[nums.length - k + 1];
        for (int i = 0; i < nums.length - k + 1; i++) {
            int[] kSize = new int[k];
            // 截取数组,参数分别为原数组,截取开始的下标,新数组,新数组开始的下标,新数组结束的下标
            System.arraycopy(nums, i, kSize, 0, k);
            Arrays.sort(kSize);
            newInt[i] = kSize[k -1];
        }
        return newInt;
    }

周兆东
107 声望21 粉丝

一个java小白的成长之路。。。