hot100 哈希

  1. 无重复字符的最长子串
    给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。

采用滑动窗口,具体算法为:
for循环里的i为窗口右值,设定一个左值为0,如果当前窗口中不包含重复元素,则右边界向右滑动,如果包含,则左边界为重复元素位置加1。
注意在选取左边界的时候,当前字符不包含在当前最长有效子段中,如:abba,我们先添加a,b进map,此时left=0,我们再添加b,发现map中包含b,而且b包含在最长有效子段中,就是1)的情况,我们更新 left=map.get(b)+1=2,此时子段更新为 b,而且map中仍然包含a,map.get(a)=0; 随后,我们遍历到a,发现a包含在map中,且map.get(a)=0,如果我们像1)一样处理,就会发现 left=map.get(a)+1=1,实际上,left此时 应该不变,left始终为2,子段变成 ba才对。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character,Integer> map = new HashMap<>();
        int max = 0;
        int left = 0;
        for(int i = 0; i < s.length();i++){
            if(map.containsKey(s.charAt(i))){
                left = Math.max(left,map.get(s.charAt(i))+1);
                
            }
            max = Math.max(max,i-left+1);
            map.put(s.charAt(i),i);
           
        }
        return max;
    }
}
  1. 电话号码的字母组合
    给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例 1:

输入:digits = “23”
输出:[“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]

递归回溯
注意add完之后不需要删除letters最后一个字母

class Solution {
    public List<String> letterCombinations(String digits) {
        
        List<String> combinations = new ArrayList<String>();
        if (digits.length() == 0) {
            return combinations;
        }
        Map<Character, String> phoneMap = new HashMap<Character, String>() {{
            put('2', "abc");
            put('3', "def");
            put('4', "ghi");
            put('5', "jkl");
            put('6', "mno");
            put('7', "pqrs");
            put('8', "tuv");
            put('9', "wxyz");
        }};
        digui(combinations,phoneMap,digits,0,new StringBuffer());
        return combinations;

    }
    public void digui(List<String> combinations,Map<Character, String> phoneMap,String digits, int index, StringBuffer letters){
        if(index == digits.length()){
            combinations.add(letters.toString());
            
            return;
        }
        String content = phoneMap.get(digits.charAt(index));
        for(int i = 0; i < content.length(); i++){
            char c = content.charAt(i);
            letters.append(c);
            digui(combinations,phoneMap,digits,index+1,letters);
            letters.deleteCharAt(index);

        }
    }

}
  1. 字母异位词分组
    给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。
示例 1:

输入: strs = [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”]
输出: [[“bat”],[“nat”,“tan”],[“ate”,“eat”,“tea”]]

思路:统计所有字母出现的频率,组成一个新的字符串
重点:StringBuffer
buffer.append(str); //添加字符

StringBuffer sb = new StringBuffer(“hello”);
sb.setCharAt(1,‘E’);
System.out.println(sb); // 输出:hEllo 替换字符

sb.reverse();//反转字符

StringBuffer sb = new StringBuffer(“She”);
sb.deleteCharAt(2);
System.out.println(sb); // 输出:Sh 删除字符

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        List<List<String>> res = new ArrayList<>();
        Map<String,List<String>> map = new HashMap<>();
        for(String str : strs){
            int length = str.length();
            int[] letters = new int[26];
            for(int i = 0; i < length; i++){
                letters[str.charAt(i)-'a']++;
            }
            StringBuffer s = new StringBuffer();
            
            for(int i = 0; i < 26; i++){
                if(letters[i]!=0){
                    s.append((char)(i+'a'));
                    s.append((char)(letters[i]+'0'));
                }
            }
            
            String ss = s.toString();
            System.out.println(ss);
            List<String> list = map.getOrDefault(ss,new ArrayList<String>());
            list.add(str);
            map.put(ss,list);
            
        }
        return new ArrayList(map.values());

    }
}
  1. 从前序与中序遍历序列构造二叉树
    给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

示例 1:

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

思路:前序遍历序列的第一个即时root,在中序中找到root,左边界到root为左子树,root到右边界为右子树。同时,确定前序序列中root的位置,左子树为当前前序序列的下一个,右子树为当前前序序列起始位置加上左子树的长度

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return digui(preorder,inorder,0,preorder.length-1,0);
    }
    public TreeNode digui(int[] preorder, int[] inorder,int left, int right,int l){
        if(left > right){
            return null;
        }
        TreeNode root = new TreeNode(preorder[l]);
        int split = 0;
        for(int i = left; i <= right; i++){
            if(inorder[i] == root.val){
                split = i;
            }
        }
        
        TreeNode leftNode = digui(preorder,inorder,left,split-1,l+1);
        TreeNode rightNode = digui(preorder,inorder,split+1,right,l+split-left+1);
        root.left = leftNode;
        root.right = rightNode;
        return root;
    }
}
  1. 最长连续序列
    给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。

思路:将所有元素放入到set中去重,并且这样可以做到o(1)查询
找到最小元素们,从他开始依次查找是否有比他大1的值

class Solution {
    public int longestConsecutive(int[] nums) {
        HashSet<Integer> set = new HashSet<>();
        int result = 0;
        for(int num: nums){
            set.add(num);
        }
        for(int num : set){
            if(set.contains(num-1)){
                continue;
            }
            else{
                int temp = num;
                int res = 1;
                while(set.contains(temp+1)){
                    res++;
                    temp++;
                }
                result = Math.max(result,res);
            }
        }
        return result;
    }
}
  1. 环形链表 II
    给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。
思路:采用双指针
fast和slow都从head开始,停止在第一次相遇的地方
另有一个指针从head开始走,fast改为每次走一格,二者相遇的地方就是环开始的地方

  1. 相交链表
    给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

思路:1 采用哈希表的方法查找重复元素
2 采用双指针,一个指向A一个指向B,A为空则A指向B的开头,B为空则指向A的开头

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }
        ListNode pA = headA, pB = headB;
        while (pA != pB) {
            pA = pA == null ? headB : pA.next;
            pB = pB == null ? headA : pB.next;
        }
        return pA;
    }
}

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/intersection-of-two-linked-lists/solution/xiang-jiao-lian-biao-by-leetcode-solutio-a8jn/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  1. 实现 Trie (前缀树)
    Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。

请你实现 Trie 类:

Trie() 初始化前缀树对象。
void insert(String word) 向前缀树中插入字符串 word 。
boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。

思路:构建一个Tire类,每个类里包含一个数组,数组中有26个Trie类,分别代表26个字母。
在insert时,遍历每个字母,如果当前类的数组相应位置为null,则new一个Trie类(这个对象同样包含26个Trie),遍历完成后,最后一个node要设置标记位,标志一个单词在这里结束

class Trie {
    private Trie[] children;
    private boolean isEnd;

    public Trie() {
        children = new Trie[26];
        isEnd = false;
    }
    
    public void insert(String word) {
        Trie node = this;
        for(int i = 0; i < word.length(); i++){
            char c = word.charAt(i);
            if(node.children[c-'a'] == null){
                node.children[c-'a'] = new Trie();
                node = node.children[c-'a'];
            }
            else{
                node = node.children[c-'a'];
            }
        }
        node.isEnd = true;

    }
    
    public boolean search(String word) {
        Trie node = startsWith1(word);
        return (node!=null)&& node.isEnd  ;

    }
    
    public boolean startsWith(String prefix) {
        return startsWith1(prefix) != null;
    }

    public Trie startsWith1(String prefix) {
        Trie node = this;
        for(int i = 0; i < prefix.length(); i++){
            char c = prefix.charAt(i);
            if(node.children[c-'a'] == null){
                return null;
            }
            else{
                node = node.children[c-'a'];
            }
        }
        return node;
    }

}

/**
 * Your Trie object will be instantiated and called as such:
 * Trie obj = new Trie();
 * obj.insert(word);
 * boolean param_2 = obj.search(word);
 * boolean param_3 = obj.startsWith(prefix);
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值