LeetCode刷题笔记(Java)---第701-720题

前言

需要开通vip的题目暂时跳过

笔记导航

点击链接可跳转到所有刷题笔记的导航链接

701. 二叉搜索树中的插入操作

给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。

注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。

在这里插入图片描述

  • 解答

    public TreeNode insertIntoBST(TreeNode root, int val) {
            if(root == null)return new TreeNode(val);
            if(root.val < val){
                root.right = insertIntoBST(root.right,val);
            }else{
                root.left = insertIntoBST(root.left,val);
            }
            return root;
        }
    
  • 分析

    1. 在叶子结点的位置插入是最简单的做法。
    2. 因为val在树中不存在,所以可以根据搜索树一直找到叶子结点的位置。
    3. 然后和叶子结点比较,插入在它的左边或者右边
  • 提交结果
    在这里插入图片描述

703. 数据流中的第 K 大元素

设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。

请实现 KthLargest 类:

  • KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。
  • int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。

在这里插入图片描述

  • 解答

    PriorityQueue<Integer> queue = new PriorityQueue<>();
        int k;
        public KthLargest(int k, int[] nums) {
            this.k = k;
            Arrays.sort(nums);
            for (int i = nums.length - 1; i >= 0 && k != 0; i--) {
                queue.add(nums[i]);
                k--;
            }
        }
    
        public int add(int val) {
            if(queue.size() < k){
                queue.add(val);
                return queue.peek();
            }
            int curMax = queue.poll();
            if (curMax > val)
                queue.add(curMax);
            else queue.add(val);
            return queue.peek();
        }
    
  • 分析

    1. 初始化的时候将数组中最大的k个数放入到最小堆中。
    2. 这样堆顶就是当前第k大的数字。
    3. 之后调用add方法,如果传入的参数比堆顶的大,那么就移除堆顶元素,将val放入堆中,否则堆不变。
  • 提交结果
    在这里插入图片描述

705. 设计哈希集合

不使用任何内建的哈希表库设计一个哈希集合

具体地说,你的设计应该包含以下的功能

  • add(value):向哈希集合中插入一个值。
  • contains(value) :返回哈希集合中是否存在这个值。
  • remove(value):将给定值从哈希集合中删除。如果哈希集合中没有这个值,什么也不做。

在这里插入图片描述

  • 解答
class MyHashSet {
    boolean[] nums;

    /** Initialize your data structure here. */
    public MyHashSet() {
        nums = new boolean[1000001];
    }
    
    public void add(int key) {
        nums[key] = true;
    }
    
    public void remove(int key) {
        nums[key] = false;
    }
    
    /** Returns true if this set contains the specified element */
    public boolean contains(int key) {
        return nums[key];
    }
}
  • 分析

    1. 低级做法
    2. 因为存储的只有数字,并且给定了值的范围,那么就一个值一个槽
  • 提交结果
    在这里插入图片描述

706. 设计哈希映射

不使用任何内建的哈希表库设计一个哈希映射

具体地说,你的设计应该包含以下的功能

  • put(key, value):向哈希映射中插入(键,值)的数值对。如果键对应的值已经存在,更新这个值。
  • get(key):返回给定的键所对应的值,如果映射中不包含这个键,返回-1。
  • remove(key):如果映射中存在这个键,删除这个数值对。

在这里插入图片描述

  • 解答

    class MyHashMap {
    
        Bucket[] buckets = new Bucket[739];
    
        /** Initialize your data structure here. */
        public MyHashMap() {
    
        }
        
        /** value will always be non-negative. */
        public void put(int key, int value) {
            int index = key % 739;
            if(buckets[index] == null){
                buckets[index] = new Bucket(key,value);
            }else{
                Bucket bucket = buckets[index];
                while(bucket.key != key && bucket.next!=null){
                    bucket = bucket.next;
                }
                if(bucket.key == key){
                    bucket.val = value;
                }else{
                    bucket.next = new Bucket(key,value);
                }
            }
        }
        
        /** Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key */
        public int get(int key) {
            int index = key % 739;
            if(buckets[index] == null)return -1;
            Bucket bucket = buckets[index];
            while(bucket != null && bucket.key != key){
                bucket = bucket.next;
            }
            if(bucket != null){
                return bucket.val;
            }
            return -1;
        }
        
        /** Removes the mapping of the specified value key if this map contains a mapping for the key */
        public void remove(int key) {
            int index = key % 739;
            if(buckets[index] == null)return;
            Bucket bucket = buckets[index];
            if(bucket.next == null && bucket.key == key){
                buckets[index] = null;
                return;
            }
            Bucket pre = null;
            while(bucket != null && bucket.key != key){
                pre = bucket;
                bucket = bucket.next;
            }
            if(bucket == null)return;
            if(pre != null){
                pre.next = bucket.next;
                bucket.next = null;
            }else{
                Bucket first = buckets[index];
                buckets[index] = first.next;
                first.next = null;
            }
        }
    }
    class Bucket{
        int key;
        int val;
        Bucket next;
        public Bucket(int key,int val){
            this.key = key;
            this.val = val;
        }
    }
    
  • 分析

    1. 采用数组+链表的形式实现。
  • 提交结果
    在这里插入图片描述

707. 设计链表

设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。

在链表类中实现这些功能:

  • get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
  • addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
  • addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
  • addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
  • deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

在这里插入图片描述

  • 解答

    public class ListNode {
      int val;
      ListNode next;
      ListNode prev;
      ListNode(int x) { val = x; }
    }
    
    class MyLinkedList {
      int size;
      // sentinel nodes as pseudo-head and pseudo-tail
      ListNode head, tail;
      public MyLinkedList() {
        size = 0;
        head = new ListNode(0);
        tail = new ListNode(0);
        head.next = tail;
        tail.prev = head;
      }
    
      /** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
      public int get(int index) {
        // if index is invalid
        if (index < 0 || index >= size) return -1;
    
        // choose the fastest way: to move from the head
        // or to move from the tail
        ListNode curr = head;
        if (index + 1 < size - index)
          for(int i = 0; i < index + 1; ++i) curr = curr.next;
        else {
          curr = tail;
          for(int i = 0; i < size - index; ++i) curr = curr.prev;
        }
    
        return curr.val;
      }
    
      /** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
      public void addAtHead(int val) {
        ListNode pred = head, succ = head.next;
    
        ++size;
        ListNode toAdd = new ListNode(val);
        toAdd.prev = pred;
        toAdd.next = succ;
        pred.next = toAdd;
        succ.prev = toAdd;
      }
    
      /** Append a node of value val to the last element of the linked list. */
      public void addAtTail(int val) {
        ListNode succ = tail, pred = tail.prev;
    
        ++size;
        ListNode toAdd = new ListNode(val);
        toAdd.prev = pred;
        toAdd.next = succ;
        pred.next = toAdd;
        succ.prev = toAdd;
      }
    
      /** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
      public void addAtIndex(int index, int val) {
        // If index is greater than the length, 
        // the node will not be inserted.
        if (index > size) return;
    
        // [so weird] If index is negative, 
        // the node will be inserted at the head of the list.
        if (index < 0) index = 0;
    
        // find predecessor and successor of the node to be added
        ListNode pred, succ;
        if (index < size - index) {
          pred = head;
          for(int i = 0; i < index; ++i) pred = pred.next;
          succ = pred.next;
        }
        else {
          succ = tail;
          for (int i = 0; i < size - index; ++i) succ = succ.prev;
          pred = succ.prev;
        }
    
        // insertion itself
        ++size;
        ListNode toAdd = new ListNode(val);
        toAdd.prev = pred;
        toAdd.next = succ;
        pred.next = toAdd;
        succ.prev = toAdd;
      }
    
      /** Delete the index-th node in the linked list, if the index is valid. */
      public void deleteAtIndex(int index) {
        // if the index is invalid, do nothing
        if (index < 0 || index >= size) return;
    
        // find predecessor and successor of the node to be deleted
        ListNode pred, succ;
        if (index < size - index) {
          pred = head;
          for(int i = 0; i < index; ++i) pred = pred.next;
          succ = pred.next.next;
        }
        else {
          succ = tail;
          for (int i = 0; i < size - index - 1; ++i) succ = succ.prev;
          pred = succ.prev.prev;
        }
    
        // delete pred.next 
        --size;
        pred.next = succ;
        succ.prev = pred;
      }
    }
    
  • 分析

  • 提交结果
    在这里插入图片描述

709. 转换成小写字母

实现函数 ToLowerCase(),该函数接收一个字符串参数 str,并将该字符串中的大写字母转换成小写字母,之后返回新的字符串。

在这里插入图片描述

  • 解答

    public String toLowerCase(String str) {
            char[] chars = str.toCharArray();
            for(int i = 0;i < chars.length;i++){
                if(chars[i] >= 'A' && chars[i] <= 'Z'){
                    chars[i] = (char)(chars[i] - 'A' + 'a');
                }
            }
            return new String(chars);
        }
    
  • 分析

  • 提交结果
    在这里插入图片描述

710. 黑名单中的随机数

给定一个包含 [0,n ) 中独特的整数的黑名单 B,写一个函数从 [ 0,n ) 中返回一个不在 B 中的随机整数。

对它进行优化使其尽量少调用系统方法 Math.random() 。

提示:

  1. 1 <= N <= 1000000000
  2. 0 <= B.length < min(100000, N)
  3. [0, N) 不包含 N,详细参见 interval notation 。

在这里插入图片描述

  • 解答

    		Map<Integer, Integer> m;
        Random r;
        int wlen;
    
        public Solution(int n, int[] b) {
            m = new HashMap<>();
            r = new Random();
            wlen = n - b.length;
            Set<Integer> w = new HashSet<>();
            for (int i = wlen; i < n; i++) w.add(i);//wlen范围外的名单
            for (int x : b) w.remove(x);//移除黑名单,剩下wlen范围外白名单
            Iterator<Integer> wi = w.iterator();迭代白名单
            for (int x : b)//遍历黑名单
                if (x < wlen)//在wlen范围内,映射到wlen范围外的白名单
                    m.put(x, wi.next());
        }
    
        public int pick() {
            int k = r.nextInt(wlen);
            return m.getOrDefault(k, k);
        }
    
  • 分析

    1. 黑名单映射
    2. wlen,白名单的长度,m用于记录黑名单映射,在wlen范围内的黑名单 映射到wlen范围外的白名单
  • 提交结果
    在这里插入图片描述

712. 两个字符串的最小ASCII删除和

给定两个字符串s1, s2,找到使两个字符串相等所需删除字符的ASCII值的最小和。

在这里插入图片描述

  • 解答

    public int minimumDeleteSum(String s1, String s2) {
            int[][] dp = new int[s1.length() + 1][s2.length() + 1];
            //初始化
            for (int i = s1.length() - 1; i >= 0; i--) {
                dp[i][s2.length()] = dp[i+1][s2.length()] + s1.codePointAt(i);
            }
            for (int j = s2.length() - 1; j >= 0; j--) {
                dp[s1.length()][j] = dp[s1.length()][j+1] + s2.codePointAt(j);
            }
            for (int i = s1.length() - 1; i >= 0; i--) {
                for (int j = s2.length() - 1; j >= 0; j--) {
                    if (s1.charAt(i) == s2.charAt(j)) {
                        dp[i][j] = dp[i+1][j+1];
                    } else {
                        dp[i][j] = Math.min(dp[i+1][j] + s1.codePointAt(i),
                                            dp[i][j+1] + s2.codePointAt(j));
                    }
                }
            }
            return dp[0][0];
        }
    
  • 分析

    1. 动态规划
    2. dp[i] [j]表示 使s1第i个之后的字符串 和s2第j个之后的字符串所需删除字符的ASCII值的最小和
    3. 首先初始化dp[i] [s2.length()] 表示删除第i个字符之后的字符串 的ASCII值之和。同理初始化dp[s1.length()] [j]
    4. 然后就是两重循环,遍历每一个dp[i] [j]
    5. s1.charAt(i) == s2.charAt(j),说明不需要删除,那么dp[i] [j] 就等于dp[i + 1] [j+1]
    6. 否则dp[i] [j] = Math.min(dp[i+1] [j] + s1.codePointAt(i),
      dp[i] [j+1] + s2.codePointAt(j))
    7. 最后返回dp[0] [0]即可
  • 提交结果
    在这里插入图片描述

713. 乘积小于K的子数组

给定一个正整数数组 nums。

找出该数组内乘积小于 k 的连续的子数组的个数。

在这里插入图片描述

  • 解答

    public int numSubarrayProductLessThanK(int[] nums, int k) {
            if (k <= 1) return 0;
            int prod = 1, ans = 0, left = 0;
            for (int right = 0; right < nums.length; right++) {
                prod *= nums[right];
                while (prod >= k) prod /= nums[left++];
                ans += right - left + 1;
            }
            return ans;
        }
    
  • 分析

    1. 双指针
    2. 一次遍历,prod维护当前满足小于k的区间乘积。
    3. ans加上以nums[right]为结尾的数字的子数组的个数。
  • 提交结果
    在这里插入图片描述

714. 买卖股票的最佳时机含手续费

给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。

你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。

返回获得利润的最大值。

注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。

在这里插入图片描述

  • 解答

    //方法1
    public int maxProfit(int[] prices, int fee) {
            int len = prices.length;
            int[][] dp = new int[len][2];
            dp[0][0] = 0;
            dp[0][1] = -prices[0];
            for(int i = 1;i < len;i++){
                for(int j = 0;j < i;j++){
                    dp[i][0] = Math.max(dp[j][0],dp[j][1] + prices[i] - fee);
                    dp[i][1] = Math.max(dp[j][1],dp[j][0] - prices[i]);
                }
            }
            return dp[len-1][0];
        }
    //方法2
    public int maxProfit(int[] prices, int fee) {
            int len = prices.length;
            int[][] dp = new int[len][2];
            dp[0][0] = 0;
            dp[0][1] = -prices[0];
            for(int i = 1;i < len;i++){
                dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i] - fee);
                dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] - prices[i]);
            }
            return dp[len-1][0];
        }
    
  • 分析

    1. 方法1 动态规划超时
    2. 方法2 动态规划,只需要考虑当前点的前一天的状态
    3. dp[i] [0] 表示第i天不持有股票的最大值 dp[i] [1] 表示持有股票的最大值。
  • 提交结果
    在这里插入图片描述

715. Range 模块

Range 模块是跟踪数字范围的模块。你的任务是以一种有效的方式设计和实现以下接口。

  • addRange(int left, int right) 添加半开区间 [left, right),跟踪该区间中的每个实数。添加与当前跟踪的数字部分重叠的区间时,应当添加在区间 [left, right) 中尚未跟踪的任何数字到该区间中。
  • queryRange(int left, int right) 只有在当前正在跟踪区间 [left, right) 中的每一个实数时,才返回 true。
  • removeRange(int left, int right) 停止跟踪区间 [left, right) 中当前正在跟踪的每个实数。

在这里插入图片描述

  • 解答

    class RangeModule {
        TreeSet<Interval> ranges;
        public RangeModule() {
            ranges = new TreeSet();
        }
    
        public void addRange(int left, int right) {
            Iterator<Interval> itr = ranges.tailSet(new Interval(0, left - 1)).iterator();
            while (itr.hasNext()) {
                Interval iv = itr.next();
                if (right < iv.left) break;
                left = Math.min(left, iv.left);
                right = Math.max(right, iv.right);
                itr.remove();
            }
            ranges.add(new Interval(left, right));
        }
    
        public boolean queryRange(int left, int right) {
            Interval iv = ranges.higher(new Interval(0, left));
            return (iv != null && iv.left <= left && right <= iv.right);
        }
    
        public void removeRange(int left, int right) {
            Iterator<Interval> itr = ranges.tailSet(new Interval(0, left)).iterator();
            ArrayList<Interval> todo = new ArrayList();
            while (itr.hasNext()) {
                Interval iv = itr.next();
                if (right < iv.left) break;
                if (iv.left < left) todo.add(new Interval(iv.left, left));
                if (right < iv.right) todo.add(new Interval(right, iv.right));
                itr.remove();
            }
            for (Interval iv: todo) ranges.add(iv);
        }
    }
    
    class Interval implements Comparable<Interval>{
        int left;
        int right;
    
        public Interval(int left, int right){
            this.left = left;
            this.right = right;
        }
    
        public int compareTo(Interval that){
            if (this.right == that.right) return this.left - that.left;
            return this.right - that.right;
        }
    }
    
  • 分析

    1. treeSet来维护所有的区间
    2. 当调用addRange的时候,先调用treeSet的tailSet得到所有区间在(0,left)之后的区间。然后遍历区间,合并重叠的区间。
    3. 当调用queryRange的时候,使用treeSet的higher得到大于(0, left)的第一个区间。判断给定的参数,是否有区间和这个区间重叠。
    4. 当调用removeRange的时候,使用treeSet的tailSet得到所有区间在(0,left)之后的区间。然后遍历,拆分区间。
  • 提交结果
    在这里插入图片描述

717. 1比特与2比特字符

有两种特殊字符。第一种字符可以用一比特0来表示。第二种字符可以用两比特(10 或 11)来表示。

现给一个由若干比特组成的字符串。问最后一个字符是否必定为一个一比特字符。给定的字符串总是由0结束。

在这里插入图片描述

  • 解答

    public boolean isOneBitCharacter(int[] bits) {
            for(int i = 0;i < bits.length;){
                if(i == bits.length - 1 && bits[i] == 0)return true;
                if(bits[i] == 1)i += 2;
                else i++;
            }
            return false;
        }
    
  • 分析

    1. 当遇到字符1的时候,则必定会跳过两位
    2. 当遇到字符0的时候,跳过一位。
    3. 当前遍历的字符是最后一位并且是0,那么返回true
    4. 否则最后返回false
  • 提交结果
    在这里插入图片描述

718. 最长重复子数组

给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。

在这里插入图片描述

  • 解答

    //方法1 暴力
    public int findLength(int[] A, int[] B) {
            int max = 0;
            int temp = 0;
            for(int i = 0;i < A.length;i++){
                for(int j = 0;j < B.length;j++){
                    int a = i,b = j;
                    while(a < A.length && b < B.length){
                        if(A[a] == B[b]){
                            temp++;
                            a++;
                            b++;
                        }else {
                            break;
                        }
                    }
                    max = Math.max(temp,max);
                    temp = 0;
                }
            }
            max = Math.max(temp,max);
            return max;
        }
    //方法2 dp
    public int findLength(int[] A, int[] B) {
            int lenA = A.length,lenB = B.length;
            int[][] dp = new int[lenA + 1][lenB + 1];
            int max = 0;
            for(int i = 0;i < lenA;i++){
                for(int j = 0;j < lenB;j++){
                    if(A[i] == B[j]){
                        dp[i + 1][j + 1] = dp[i][j] + 1;
                        max = Math.max(dp[i + 1][j + 1],max);
                    }
                }
            }
            return max;
        }
    //方法3
    public int findLength(int[] A, int[] B) {
            if (A.length < B.length)
                return findLengthHelper(A, B);
            return findLengthHelper(B, A);
        }
    
        public int findLengthHelper(int[] A, int[] B) {
            int aLength = A.length, bLength = B.length;
            //total是总共运行的次数
            int total = aLength + bLength - 1;
            int max = 0;
            for (int i = 0; i < total; i++) {
                //下面一大坨主要判断数组A和数组B比较的起始位置和比较的长度
                int aStart = 0;
                int bStart = 0;
                int len = 0;
                if (i < aLength) {
                    aStart = aLength - i - 1;
                    bStart = 0;
                    len = i + 1;
                } else {
                    aStart = 0;
                    bStart = i - aLength + 1;
                    len = Math.min(bLength - bStart, aLength);
                }
                if(len > max){
                    int maxlen = maxLength(A, B, aStart, bStart, len);
                    max = Math.max(max, maxlen);
                }
            }
            return max;
        }
        public int maxLength(int[] A, int[] B, int aStart, int bStart, int len) {
            int max = 0, count = 0;
            for (int i = 0; i < len; i++) {
                if (A[aStart + i] == B[bStart + i]) {
                    count++;
                    max = Math.max(max, count);
                } else {
                    count = 0;
                }
            }
            return max;
        }
    
  • 分析

    1. 方法1 暴力
    2. 方法2 动态规划
    3. dp[i] [j]表示A中第i个数字结尾的子数组和B中第j个数字结尾的子数组中公共的长度最长的子数组的长度。
    4. 转移方程 当A[i] == B[j]时 dp[i + 1] [j + 1] = dp[i] [j] + 1
    5. 方法3 滑动窗口 如下图所示 以此类推
      在这里插入图片描述
  • 提交结果

    方法1
    在这里插入图片描述

    方法2
    在这里插入图片描述

    方法3
    在这里插入图片描述

719. 找出第 k 小的距离对

给定一个整数数组,返回所有数对之间的第 k 个最小距离。一对 (A, B) 的距离被定义为 A 和 B 之间的绝对差值。

在这里插入图片描述

  • 解答

    public int smallestDistancePair(int[] nums, int k) {
            Arrays.sort(nums);
            int max = nums[nums.length - 1] - nums[0];
            int low = 0;
            int high = max;
            while(low < high){
                int mid = low + ((high - low) >> 1);
                int left = 0;
                int count = 0;
                for(int right = 0;right < nums.length;right++){
                    while(nums[right] - nums[left] > mid)left++;
                    count += right - left;
                }
                if(count >= k){
                    high = mid;
                }else{
                    low = mid + 1;
                }
            }
            return low;
        }
    
  • 分析

    1. 二分查找,先将数组排序。
    2. 这样可以得到最大的数对距离
    3. 第k个最小距离的数对,一定在 0 ~ 最大数对距离之间。
    4. 那么就用二分查找找到这个数,满足是第k个最小距离的数对即可。中间的for循环就是用来判断是有多少个小于等于mid的数对。
  • 提交结果在这里插入图片描述

720. 词典中最长的单词

给出一个字符串数组words组成的一本英语词典。从中找出最长的一个单词,该单词是由words词典中其他单词逐步添加一个字母组成。若其中有多个可行的答案,则返回答案中字典序最小的单词。

若无答案,则返回空字符串。
在这里插入图片描述

  • 解答

    //方法1
    class Solution {
        public String longestWord(String[] words) {
            Arrays.sort(words,new Comparator<String>(){
                public int compare(String s1,String s2){
                    if(s1.length() != s2.length()){
                        return s1.length() - s2.length();
                    }
                    for(int i = 0;i < s1.length();i++){
                        if(s1.charAt(i) > s2.charAt(i))
                            return 1;
                        else if(s1.charAt(i) < s2.charAt(i))
                            return -1;
                    }
                    return 0;
                }
            });
            TrieTree tree = new TrieTree();
            int max = 0;
            String res = "";
            for(String word : words){
                TrieTree t = tree;
                for(int i = 0;i < word.length();i++){
                    if(word.length() == 1){
                        if(t.children[word.charAt(i) - 'a'] == null){
                            t.children[word.charAt(i) - 'a'] = new TrimTree();
                        }
                        if(max == 0){
                            max = 1;
                            res = word;
                        }
                    }else{
                        if(i != word.length() - 1){
                            if(t.children[word.charAt(i) - 'a'] == null)break;
                            t = t.children[word.charAt(i) - 'a'];
                        }else{
                            if(t.children[word.charAt(i) - 'a'] == null){
                                t.children[word.charAt(i) - 'a'] = new TrieTree();
                            }
                            if(word.length() > max){
                                max = word.length();
                                res = word;
                            }
                        }
                    }
                }
            }
            return res;
        }
    }
    
    class TrieTree{
        TrieTree[] children;
        public TrieTree(){
            children = new TrieTree[26];
        }
    }
    
  • 分析

    1. 方法1 前缀树,来维护可以逐步添加得到的字符串。然后从中找到最长的。
  • 提交结果在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值