- 无重复字符的最长子串
给定一个字符串 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;
}
}
- 电话号码的字母组合
给定一个仅包含数字 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:
输入: 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());
}
}
- 从前序与中序遍历序列构造二叉树
给定两个整数数组 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;
}
}
- 最长连续序列
给定一个未排序的整数数组 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;
}
}
- 环形链表 II
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
思路:采用双指针
fast和slow都从head开始,停止在第一次相遇的地方
另有一个指针从head开始走,fast改为每次走一格,二者相遇的地方就是环开始的地方
- 相交链表
给你两个单链表的头节点 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)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 实现 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);
*/