leetcode之哈希表刷题总结1
1-两数之和
题目链接:题目链接这里!!!
思路:本题不难,但也没有想象的那么简单,需要使用hash表,把时间复杂度控制到O(n)内。不用hash表直接暴力就是O(n^2)的复杂度,会超时。
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> map = new HashMap<>() ;
int [] res = new int [2] ;
for(int i=0; i<nums.length; i++){
map.put(target-nums[i],i) ;
}
for(int i=0; i<nums.length; i++){
if(map.containsKey(nums[i])){
res[0] = i ;
res[1] = map.get(nums[i]) ;
if(res[0]!=res[1]){
return res ;
}
}
}
return res ;
}
}
2-有效的数独
题目链接:题目链接戳这里!!!
思路:三个数组标记,分别标记每个元素再对应的行,列,3*3方格的出现次数。
class Solution {
public boolean isValidSudoku(char[][] board) {
int [][] row = new int [9][9] ;
int [][] column = new int [9][9] ;
int [][][] vis = new int [3][3][9] ;
for(int i=0; i<9; i++){
for(int j=0; j<9; j++){
if(board[i][j] != '.'){
int idx = board[i][j] - '0' - 1 ;
row[i][idx] ++ ;
column[j][idx] ++ ;
vis[i/3][j/3][idx] ++ ;
if(row[i][idx]>1 || column[j][idx]>1 || vis[i/3][j/3][idx]>1){
return false ;
}
}
}
}
return true ;
}
}
3-矩阵置零
题目链接:题目链接戳这里!!!
思路1:使用行标记数组和列标记数组,记录出现0的行列,再次遍历遇到该行或者该列,修改数组元素为0即可,不过题目要求空间复杂度为O(1),即不开辟额外的存储空间,我们需要思路2。
class Solution {
public void setZeroes(int[][] matrix) {
int [] row = new int [matrix.length] ;
int [] column = new int [matrix[0].length] ;
for(int i=0; i<matrix.length; i++){
for(int j=0; j<matrix[0].length; j++){
if(matrix[i][j] == 0){
row[i] = 1 ;
column[j] = 1 ;
}
}
}
for(int i=0; i<matrix.length; i++){
for(int j=0; j<matrix[0].length; j++){
if(row[i]==1 || column[j]==1){
matrix[i][j] = 0 ;
}
}
}
}
}
思路2:我们可以用矩阵的第一行和第一列代替方法一中的两个标记数组,以达到O(1) 的额外空间。但这样会导致原数组的第一行和第一列被修改,无法记录它们是否原本包含 0。因此我们需要额外使用两个标记变量分别记录第一行和第一列是否原本包含 0。
在实际代码中,我们首先预处理出两个标记变量,接着使用其他行与列去处理第一行与第一列,然后反过来使用第一行与第一列去更新其他行与列,最后使用两个标记变量更新第一行与第一列即可。
class Solution {
public void setZeroes(int[][] matrix) {
boolean row = false, column = false ;
for(int i=0; i<matrix.length; i++){
if(matrix[i][0]==0){
column = true ;
}
}
for(int j=0; j<matrix[0].length; j++){
if(matrix[0][j]==0){
row = true ;
}
}
for(int i=1; i<matrix.length; i++){
for(int j=1; j<matrix[0].length; j++){
if(matrix[i][j] == 0){
matrix[i][0] = 0;
matrix[0][j] = 0 ;
}
}
}
for(int i=1; i<matrix.length; i++){
for(int j=1; j<matrix[0].length; j++){
if(matrix[i][0]==0 || matrix[0][j]==0){
matrix[i][j] = 0 ;
}
}
}
if(row){
for(int j=0; j<matrix[0].length; j++){
matrix[0][j] = 0 ;
}
}
if(column){
for(int i=0; i<matrix.length; i++){
matrix[i][0] = 0 ;
}
}
}
}
4-存在重复元素
题目链接:题目链接戳这里!!!
思路1:hashmap存储每个元素,如果第一次出现,则存储,否则返回true
class Solution {
public boolean containsDuplicate(int[] nums) {
Map<Integer, Integer> map = new HashMap<>() ;
for(int i=0; i<nums.length; i++){
if(map.get(nums[i])==null){
map.put(nums[i],1) ;
}else{
return true ;
}
}
return false ;
}
}
思路2:用set集合的去重机制,比较去重后的集合大小和原数组大小是否一致。
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<>() ;
for(int i=0; i<nums.length; i++){
set.add(nums[i]) ;
}
return (set.size()==nums.length) ? false : true ;
}
}
思路3:先排序,再比较有没有连个相邻元素相等。
class Solution {
public boolean containsDuplicate(int[] nums) {
Arrays.sort(nums) ;
for(int i=1; i<nums.length; i++){
if(nums[i-1]==nums[i]){
return true ;
}
}
return false ;
}
}
5-求众数
题目链接:题目链接戳这里!!!
思路1:使用hashmap存储每个元素出现的次数,只要大于n/3次的,存到set集合。
class Solution {
public List<Integer> majorityElement(int[] nums) {
int n = nums.length ;
Set<Integer> set = new TreeSet<>() ;
Map<Integer,Integer> map = new HashMap<>() ;
for(int i=0; i<nums.length; i++){
map.put(nums[i],map.getOrDefault(nums[i],0)+1) ;
}
for(int i=0; i<nums.length; i++){
if(map.get(nums[i]) > n/3){
set.add(nums[i]) ;
}
}
return new ArrayList<>(set) ;
}
}
思路2:hashmap存储每个元素的出现次数,如果大于n/3,且该元素不在list集合中,则存入。
class Solution {
public List<Integer> majorityElement(int[] nums) {
int n = nums.length ;
List<Integer> list = new ArrayList<>() ;
Map<Integer,Integer> map = new HashMap<>() ;
for(int i=0; i<nums.length; i++){
map.put(nums[i],map.getOrDefault(nums[i],0)+1) ;
}
for(int i=0; i<nums.length; i++){
if(map.get(nums[i]) > n/3 && !list.contains(nums[i])){
list.add(nums[i]) ;
}
}
return list;
}
}
6-回文排列
题目链接:题目链接戳这里!!!
思路:用set集合存储元素,如果第一次出现就存储,否则就删除,如果最后存在大于等于2个不一样的元素,则不是回文排列,反之是回文排列。
class Solution {
public boolean canPermutePalindrome(String s) {
Set<Character> set = new HashSet<>() ;
for(int i=0; i<s.length(); i++){
if(set.contains(s.charAt(i))){
set.remove(s.charAt(i)) ;
}else{
set.add(s.charAt(i)) ;
}
}
return set.size()<=1 ;
}
}
7-递增子序列
题目链接:题目链接戳这里!!!
思路:递归+回溯
其实就是递归找出所有的子集,防止出现重复的情况,
如果当前元素大于等于上一个选择的元素,则选择,也可以不选择。
如果当前的元素不等于上一个选择元素,才考虑可以不选。
即大于的时候,可以选,也可以不选,等于的时候必须选,不等于的时候可以不选。
class Solution {
List<Integer> temp = new ArrayList<>() ;
List<List<Integer>> ans = new ArrayList<>() ;
public List<List<Integer>> findSubsequences(int[] nums) {
//递归+回溯
dfs(nums,0,Integer.MIN_VALUE) ;
return ans ;
}
public void dfs(int [] nums, int cur, int pre){
if(cur==nums.length){
if(temp.size()>=2){
ans.add(new ArrayList<>(temp)) ;
}
return ;
}
if(nums[cur] >= pre){
temp.add(nums[cur]) ;
dfs(nums,cur+1,nums[cur]) ;
temp.remove(temp.size()-1) ;
}
if(nums[cur] != pre){
dfs(nums,cur+1,pre) ;
}
}
}
8-快乐数
题目链接:题目链接戳这里!!!
思路:用set集合判重,如果这个数再次出现,则返回false,否则一直求下去,直至等于1.
class Solution {
public boolean isHappy(int n) {
Set<Integer> set = new HashSet<>() ;
while(n!=1 && !set.contains(n)){
set.add(n) ;
n = f(n) ;
}
return n==1 ;
}
public int f(int n){
String s = String.valueOf(n) ;
int sum = 0 ;
for(int i=0; i<s.length(); i++){
sum += (s.charAt(i) - '0')*(s.charAt(i) - '0') ;
}
return sum ;
}
}
9-单词规律
题目链接:题目链接戳这里!!!
思路:用hashmap存储pattern的每个字符和str对应的字符串,如如果str的长度和pattern的长度不同则返回false,如果字符串出现过,字符没出现,则返回false,如果字符没出现,则将字符和对应的字符串存入map中,如果字符出现且map中对应的字符串不等于str[i],则返回false。
class Solution {
public boolean wordPattern(String pattern, String s) {
Map<Character,String> map = new HashMap<>() ;
String [] str = s.split("[ ]") ;
if(str.length!=pattern.length()){
return false ;
}
for(int i=0; i<pattern.length(); i++){
if(map.containsValue(str[i]) && !map.containsKey(pattern.charAt(i))){
return false ;
}
if(!map.containsKey(pattern.charAt(i)) ){
map.put(pattern.charAt(i),str[i]) ;
}else{
if(!map.get(pattern.charAt(i)).equals(str[i])){
return false ;
}
}
}
return true ;
}
}
10-两个数组的交集
题目链接:题目链接戳这里!!!
思路:set集合去重,判断交集即可。
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> set1 = new HashSet<>() ;
Set<Integer> set2 = new HashSet<>() ;
List<Integer> res = new ArrayList<>() ;
for(int i=0; i<nums1.length; i++){
set1.add(nums1[i]) ;
}
for(int i=0; i<nums2.length; i++){
set2.add(nums2[i]) ;
}
List<Integer> list = new ArrayList<>(set2) ;
for(int i=0; i<list.size(); i++){
if(set1.contains(list.get(i))){
res.add(list.get(i)) ;
}
}
if(res.size()==0){
return new int []{} ;
}
int [] ans = new int [res.size()] ;
int j = 0 ;
for(int sets : res){
ans[j++] = sets ;
}
return ans ;
}
}