ProblemSet of Hash Algorithms

1044. Longest Duplicate Substring

typedef unsigned long long ULL;
const int N=100010,base=131;
ULL POW[N],HASH[N];
set<ULL> record;
int startIndex;
using namespace std;

class Solution {
    
public:
    
    
    ULL getHash(int i,int j){
        return HASH[j]-HASH[i-1]*POW[j-i+1];
    }  
    
    
    string longestDupSubstring(string S) 
    {
        record.clear();
        int n=S.size();
        POW[0]=1;
        for(int i=1;i<=n;i++)
        {
            POW[i]=POW[i-1]*base;
            HASH[i]=HASH[i-1]*base+S[i-1]-'a'+1;
        }
        
        int maxLen=0;
        startIndex=-1;
        int l=0,r=n-1;
        while(l<r)
        {    
            int mid=(l+r+1)>>1;
            if(check(S,mid))
                l=mid;
            else
                r=mid-1;
        }
        return startIndex==-1?"":S.substr(startIndex,l);
    }
    
    
    /*
    如果不存在mid长度的重复子串,则r=mid-1;
    如果存在,则l=mid;
    */
    bool check(string& s,int len)
    {
        int n=s.size();
        for(int start=0;start+len-1<n;start++)
        {
            int end=start+len-1;
            ULL hash=getHash(start+1,end+1);
            if(record.count(hash))
            {
                startIndex=start;
                return true;
            }
            else
                record.insert(hash);
        }
        return false;
    }
    /*
    string longestDupSubstring(string S) {
        record.clear();
        int n=S.size();
        POW[0]=1;
        
        for(int i=1;i<=n;i++){
            POW[i]=POW[i-1]*base;
            HASH[i]=HASH[i-1]*base+S[i-1]-'a'+1;
        }
        int startIndex=-1;
        int maxLen=0;
        for(int len=1;len<=n;len++)
        {
            for(int start=0;start+len-1<n;start++)
            {
                int end=start+len-1;
                ULL hash=getHash(start+1,end+1);
                if(record.count(hash)==1 && maxLen<len)
                {
                    startIndex=start;
                    maxLen=len;
                }
                else
                    record.insert(hash);
            }
        }
        
        return startIndex==-1?"":S.substr(startIndex,maxLen);
    }
    
    */
};

954. Array of Doubled Pairs
算法一:考虑到原来数组中整数有上限,,所以用数组下标来做hash。值得注意的是,这个问题优化的地方有0值的剔除和正负数的分开讨论。

class Solution {
    public boolean canReorderDoubled(int[] A) {
        int[] recordPos=new int[100005],recordNeg=new int[100005];
        int n_zeros=0;
        for(int i=0;i<A.length;i++){
            if(A[i]==0){
                n_zeros++;
            }
            else if(A[i]<0)
            {
                recordNeg[-A[i]]++;
            }
            else
                recordPos[A[i]]++;
        }
        if((n_zeros & 1)==1)
            return false;
        
        for(int i=0;i<100005;i++){
            
            for(int j=0;j<2;j++){
                int[] tmp=j==0?recordPos:recordNeg;
                if(tmp[i]==0)
                    continue;
                if(2*i<100005 && tmp[2*i]<tmp[i])
                    return false;
                //tmp[i]=0;
                tmp[2*i]-=tmp[i];
            }
        }
        return true;
    }
}

算法二:
直接用HashMap来做

class Solution {
    public boolean canReorderDoubled(int[] A) {
        
        int n_zeros=0;
        HashMap<Integer,Integer> map=new HashMap<>();
        for(int i:A){
            if(i==0)
                n_zeros++;
            else{
                map.put(i,map.getOrDefault(i,0)+1);
            }
        }
        if((n_zeros &1)==1)
            return false;
        if(map.size()==0)
            return true;
        
        ArrayList<Integer> values=new ArrayList<>(map.keySet());
        Collections.sort(values);
        int l=0,r=values.size()-1;
        while(l<r){
            int idx=values.get(l)>0?r:l;
            int val=values.get(idx);
            int count=map.get(val);
            if(count>0)
            {
                if((val & 1)==1)
                    return false;
                int target=val/2;
                if(map.getOrDefault(target,0)==0 || map.getOrDefault(target,0)<map.get(val))
                    return false;
                map.put(target,map.get(target)-map.get(val));
                
            }
            if(idx==r)
                r--;
            else
                l++;    
        }
        return map.get(values.get(l)) == 0;
    }
}

1016. Binary String With Substrings Representing 1 To N
这个问题看了一下可以使用Rollinghash来做,就是将子串对应的hash值都计算出来,然后存起来,再对1~N的二进制表达求哈希值来判断是否存在即可。理论算法复杂度为O(N),跟上面的代码一致。这里我采用O(N^2)的暴力方法来算

class Solution {
    public boolean queryString(String S, int N) {
        int m=S.length();
        int[][] dp=new int[m][m];
        HashSet<Integer> set=new HashSet<>();
        for(int i=0;i<m;i++)
        {
            dp[i][i]=S.charAt(i)-'0';
            set.add(dp[i][i]);
        }
            
        for(int i=0;i<m;i++){
            for(int j=i+1;j<m;j++){
                dp[i][j]=dp[i][j-1]*2+S.charAt(j)-'0';
                set.add(dp[i][j]);
            }
        }
        for(int i=1;i<=N;i++)
        {
            if(!set.contains(i))
                return false;
        }
        return true;
    }
}

还有值得优化的算法:我们知道这样一个数学结论,对于1~N里面的数,[N/2,N]的数的二进制表达必然覆盖[1,N/2]的二进制表达。

class Solution {
public static boolean queryString(String S, int N) {

		for (int i =N/2; i <= N; ++i) {
            if(i==0)
                continue;
			int index = S.indexOf(Integer.toBinaryString(i));
			if (index == -1)
				return false;
		}
		return true;
	}
}

1147. Longest Chunked Palindrome Decomposition
最长成块回文分解
算法一:

class Solution {
    
    public int longestDecomposition(String s) {
        
        int l=0,r=s.length()-1;
        String left="",right="";
        int res=0;
        while(l<r)
        {
            
            left=left+s.charAt(l);
            right=s.charAt(r)+right;            
            if(left.equals(right)){
                
                res+=2;
                left="";
                right="";
            }
            l++;
            r--;
        }
        if(left=="" && l==r)
            res++;
        if(l>=r && left!=""){
            res++;
        }
        return res;
    }
}

算法二:使用hash来代替字符串,加快处理速度。

class Solution {
    
    public int longestDecomposition(String s) {
        
        int l=0,r=s.length()-1;
        int leftHash=0,rightHash=0,cur=1;
        int res=0;
        while(l<r)
        {
            
            leftHash=leftHash*26+s.charAt(l)-'a';
            rightHash=(s.charAt(r)-'a')*cur+rightHash;
            cur*=26;
            
            if(leftHash==rightHash){
                
                res+=2;
                leftHash=0;
                rightHash=0;
                cur=1;
            }
            
            l++;
            r--;
             
        }
        if(l>r && leftHash!=rightHash)
            res++;
        if(l==r){
            res++;
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值