1.有效的字母异位词(简单)
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram" 输出: true 示例 2:
输入: s = "rat", t = "car" 输出: false
哈希表
//数组
class Solution {
public boolean isAnagram(String s, String t) {
if(s.length()!=t.length())return false;
int[] arr = new int[128];
for(char sh : s.toCharArray())arr[sh]++;
for(char th : t.toCharArray()){
arr[th]--;
if(arr[th]<0)return false;
}
return true;
}
}
//Map
class Solution {
public boolean isAnagram(String s, String t) {
if(s.length()!=t.length())return false;
Map<Character,Integer> map = new HashMap<>();
for(char sh:s.toCharArray())map.put(sh,map.getOrDefault(sh,0)+1);
for(char th:t.toCharArray()){
map.put(th,map.getOrDefault(th,0)-1);
if(map.get(th) < 0)return false;
}
return true;
}
}
2.赎金信(简单)
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
示例 1:
输入:ransomNote = "a", magazine = "b" 输出:false 示例 2:
输入:ransomNote = "aa", magazine = "ab" 输出:false 示例 3:
输入:ransomNote = "aa", magazine = "aab" 输出:true
//同样哈希表数组和map
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int[] arr = new int[26];
for(char m:magazine.toCharArray())arr[m-'a']++;
for(char r:ransomNote.toCharArray()){
arr[r-'a']--;
if(arr[r-'a']<0)return false;
}
return true;
}
}
3.字母异位词分组(中等)
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。
示例 1:
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"] 输出: [["bat"],["nat","tan"],["ate","eat","tea"]] 示例 2:
输入: strs = [""] 输出: [[""]] 示例 3:
输入: strs = ["a"] 输出: [["a"]]
//哈希表Map
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
Map<String,List<String>> map =new HashMap<>();
for(String s:strs){
char[] sh = s.toCharArray();
Arrays.sort(sh);//排个序,这样字母相同的字符串就相同了
String str = Arrays.toString(sh);//排完序的转换成字符串
List<String> strList = map.getOrDefault(str,new ArrayList<String>());//查找是否有该字符串,没有就new一个
strList.add(s);//把当前的字符串对应的原字符串加入到之前的或者刚new的字符串中
map.put(str,strList);//hash表存储
}
return new ArrayList<List<String>>(map.values());//返回value即可
}
}
4.找到字符串中所有字母异位词(中等)
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例 1:
输入: s = "cbaebabacd", p = "abc" 输出: [0,6] 解释: 起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。 起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。 示例 2:
输入: s = "abab", p = "ab" 输出: [0,1,2] 解释: 起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。 起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。 起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
滑动窗口(类似于之前的覆盖子字符串问题)
(1)先将目标字符串存储到tmp中;
(2)开始滑动:
右边界寻找在tmp中的字符,有的话(即>0)就弹出,并向右继续扩张;扩张时判断大小是否和目标字符串长度一致,一致则可以添加左边界起始点。
没有的话(即=0)则停止扩张,并将左边界收缩,将之前弹出的弹入。
收缩:收缩有两种情况右边界字符为陌生字符或者已弹出字符。
陌生字符时,需要将左边界收缩到与右边界重合(窗口长度为0)时,右边界才能扩张。因为重合时才能将当前字符弹入,这样右边界才满足扩张条件(>0);
已弹出字符时:将左边界收缩到弹入右边界这个已弹出字符的位置即可,这个时候右边界就满足继续扩张的条件了。
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> res = new ArrayList<Integer>();
char[] tmp = new char[26];
for(char ph : p.toCharArray())tmp[ph-'a']++;
int n = p.length(),m = s.length();
int start=0,end=0;
while(end<m){
if(tmp[s.charAt(end)-'a']>0){
tmp[s.charAt(end++)-'a']--;//右边界扩张,弹出
if(end-start==n)res.add(start);//添加起点
}else tmp[s.charAt(start++)-'a']++;//左边界收缩,弹入
}
return res;
}
}
5.两个数组的交集(简单)
给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2] 输出:[2] 示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4] 输出:[9,4] 解释:[4,9] 也是可通过的
题意:找出两个数组的非重复元素交集。
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> res = new HashSet<>();
Set<Integer> set = new HashSet<>();
for(int num:nums1){//存储任意一个
set.add(num);
}
for(int num:nums2){
if(set.contains(num))res.add(num);//查找另一个
}
int[] result = new int[res.size()];
int i=0;
for(int n:res){//返回的数组,Set转数组
result[i++]=n;
}
return result;
}
}
6.两数之和(简单)
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。 示例 2:
输入:nums = [3,2,4], target = 6 输出:[1,2] 示例 3:
输入:nums = [3,3], target = 6 输出:[0,1]
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> map = new HashMap<>();//为了方便存下标使用Map
for(int i=0;i<nums.length;i++){
if(map.containsKey(target-nums[i]))return new int[]{map.get(target-nums[i]),i};//如果包含差值就说明当前与差值下标即为所求
else map.put(nums[i],i);
}
return new int[0];
}
}
7.四数相加 II(中等)
给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:
0 <= i, j, k, l < n nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
示例 1:
输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2] 输出:2 解释: 两个元组如下:
(0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
(1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0 示例 2:
输入:nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0] 输出:1
a+b+c+d=0转换为a+b=-(c+d),使用哈希表存储并查询
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int count=0;
Map<Integer,Integer> map = new HashMap<>();
for(int num1:nums1){
for(int num2:nums2){
map.put(num1+num2,map.getOrDefault(num1+num2,0)+1);//存储
}
}
for(int num1:nums3){
for(int num2:nums4){
if(map.containsKey(-(num1+num2)))count+=map.get(-(num1+num2));//有则累计次数
}
}
return count;
}
}
8.三数之和(中等)
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 示例 2:
输入:nums = [] 输出:[] 示例 3:
输入:nums = [0] 输出:[]
排序+三指针(位移指针,查找双指针)
初始确定长度小于3即不存在。
(1)排序;确定小的在左边,大的在右边,并确定1种终止情况:
当位移指针指向大于0的数时,说明后续都大于0,不存在和为0的三个数。
(2)查找
如果遇到与位移指针所指前一位相邻数(计算过)相同时跳过;为什么不用nums[k]==nums[k+1]呢?因为前一位的必定包括后一位的(后面的是前面的子集),去重操作,能和后一位成立的必定和前一位也成立,所以用后面一位去重
查找双指针分别指向位移指针后面一位和最后一位
和为三个指针指向的数之和
当和<0时,i++,此时可以去重while(nums[i]==nums[++i]&&i<j),不去重也可以,只是所需判断的时间花费的地方不同。
当和>0时,j--,同样去重while(nums[j]==nums[--j]&&i<j)
和==0时,加入结果集合,并继续移动两个指针并去重,这里一定去重,不然会有重复,上面可以不用去重原因是因为还不用加到结果集合中。
两种方法大同小异
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
//排序
Arrays.sort(nums);
if(nums.length<3)return new ArrayList<List<Integer>>();
List<List<Integer>> res= new ArrayList<>();
for(int k=0;k<nums.length-2;k++){
if(nums[k]>0)break;
if(k>0&&nums[k]==nums[k-1])continue;//位移指针去重
int i=k+1,j=nums.length-1;
while(i<j){
int sum=nums[k]+nums[i]+nums[j];
if(sum==0){
res.add(Arrays.asList(nums[k],nums[i],nums[j]));
while(i<j&&nums[i]==nums[++i]);//查找左指针去重
while(i<j&&nums[j]==nums[--j]);//查找右指针去重
}else if(sum<0){
while(nums[i]==nums[++i]&&i<j);//查找左指针去重
}else{
while(nums[j]==nums[--j]&&i<j);//查找右指针去重
}
}
}
return res;
}
}
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
//排序
Arrays.sort(nums);
if(nums.length<3)return new ArrayList<List<Integer>>();
List<List<Integer>> res= new ArrayList<>();
for(int k=0;k<nums.length-2;k++){
if(nums[k]>0)break;
if(k>0&&nums[k]==nums[k-1])continue;//位移指针去重
int i=k+1,j=nums.length-1;
while(i<j){
int sum=nums[k]+nums[i]+nums[j];
if(sum==0){
res.add(Arrays.asList(nums[k],nums[i],nums[j]));
while(i<j&&nums[i]==nums[i+1])i++;//查找左指针去重
while(i<j&&nums[j]==nums[j-1])j--;//查找右指针去重
i++;
j--;
}else if(sum<0){
i++;
}else{
j--;
}
}
}
return res;
}
}
9.四数之和(中等)
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n a、b、c 和 d 互不相同 nums[a] + nums[b] + nums[c] + nums[d] == target 你可以按 任意顺序 返回答案 。
示例 1:
输入:nums = [1,0,-1,0,-2,2], target = 0 输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]] 示例 2:
输入:nums = [2,2,2,2,2], target = 8 输出:[[2,2,2,2]]
//方法同上一题三数之和一样,在基础之上在嵌套一层位移指针,但是注意目标值为target,非0,所以不需要>0时break,并且内部的位移指针要在上一层的位移指针基础上位移,查找双指针不变。
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
if(nums.length<4)return new ArrayList<>();
Arrays.sort(nums);
List<List<Integer>> res =new ArrayList<>();
for(int h=0;h<nums.length-3;h++){
if(h>0&&nums[h]==nums[h-1])continue;
for(int k=h+1;k<nums.length-2;k++){
if(k>h+1&&nums[k]==nums[k-1])continue;
int i=k+1,j=nums.length-1;
while(i<j){
int sum=nums[h]+nums[k]+nums[i]+nums[j];
if(sum>target)while(i<j&&nums[j]==nums[--j]);
else if(sum<target)while(i<j&&nums[i]==nums[++i]);
else{
res.add(Arrays.asList(nums[h],nums[k],nums[i],nums[j]));
while(i<j&&nums[i]==nums[++i]);
while(i<j&&nums[j]==nums[--j]);
}
}
}
}
return res;
}
}
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
if(nums.length<4)return new ArrayList<>();
Arrays.sort(nums);
List<List<Integer>> res =new ArrayList<>();
for(int h=0;h<nums.length-3;h++){
if(h>0&&nums[h]==nums[h-1])continue;
for(int k=h+1;k<nums.length-2;k++){
if(k>h+1&&nums[k]==nums[k-1])continue;
int i=k+1,j=nums.length-1;
while(i<j){
int sum=nums[h]+nums[k]+nums[i]+nums[j];
if(sum>target)j--;
else if(sum<target)i++;
else{
res.add(Arrays.asList(nums[h],nums[k],nums[i],nums[j]));
while(i<j&&nums[i]==nums[++i]);
while(i<j&&nums[j]==nums[--j]);
}
}
}
}
return res;
}
}
链接:https://leetcode-cn.com
来源:力扣(LeetCode)