LeetCode 1307 口算难题
这道题就是给出字符串,字符串中的每一个字符代表一个数字,字符和数字是一一对应的,且保证不同的字符最多有十种,问给出的字符串是否存在映射使加法成立。描述的可能不是很清楚,详见原题---LeetCode 1307 口算难题。这道题是dfs+剪枝,纯暴力时间开销很大,我的想法是从每个字符串的最低位依次枚举,也就是依次枚举个位、十位、百位......然后到等式右边的时候,也就是结果,判定当前字符是否已经映射,是否可以映射成为等式左边几个数相加的和,这里的和只取个位就可以,因为我是按位枚举的,还有一点要注意的是进位,并且到最后判断是否有数字出现前导0,我在预处理数据时把所有的字符串倒置了,方便接下来的运算。整体有一定难度,更重要的是所有的细节都要考虑到,很棒的一道题。
class Solution {
public:
int mp[300],rsct;
int wdsz[10],wdct;
int vis[10],jinwei[10],maxn;
bool dfs(int now,int pos,vector<string>& words, string result)
//第几个数字,第几位
{
if(pos==maxn)
{
for(int i=0;i<wdct;i++)
if(mp[words[i][wdsz[i]-1]]==0) return false;
if(mp[result[rsct-1]]==0) return false;
return true;
}
if(now<wdct)
{
if(pos<wdsz[now])
{
if(mp[words[now][pos]]==-1)
{
for(int i=0;i<10;i++)
if(!vis[i])
{
vis[i]=1;
mp[words[now][pos]]=i;
if(dfs(now+1,pos,words,result)) return true;
mp[words[now][pos]]=-1;
vis[i]=0;
}
}
else
{
if(dfs(now+1,pos,words,result)) return true;
}
}
else
{
if(dfs(now+1,pos,words,result)) return true;
}
}
else if(now==wdct)
{
int ans=0;
for(int i=0;i<wdct;i++)
{
if(pos<wdsz[i]) ans+=mp[words[i][pos]];
}
if(pos>0) ans+=jinwei[pos-1];
jinwei[pos]=ans/10;
ans=ans%10;
if(rsct<=pos)
{
if(ans!=0) return false;
else return dfs(0,pos+1,words,result);
}
else
{
if(mp[result[pos]]==-1)
{
if(vis[ans]==1) return false;
else
{
vis[ans]=1;
mp[result[pos]]=ans;
if(dfs(0,pos+1,words,result)) return true;
vis[ans]=0;
mp[result[pos]]=-1;
}
}
else
{
if(mp[result[pos]]!=ans) return false;
else return dfs(0,pos+1,words,result);
}
}
}
return false;
}
bool isSolvable(vector<string>& words, string result) {
wdct=words.size();
rsct=result.size();
maxn=rsct;
memset(mp,-1,sizeof(mp));
for(int i=0;i<wdct;i++)
{
wdsz[i]=words[i].size();
reverse(words[i].begin(),words[i].end());
maxn=max(wdsz[i],maxn);
}
reverse(result.begin(),result.end());
return dfs(0,0,words,result);
}
};