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;
}
}