最近網上出了一個比較火的刑偵推理題,王二比較感興趣,於是抽空做了做。
一、推理題如下
二、遇到的問題
剛開始,王二寫下了如下程式碼:
<script>
var arr = new Array(10).fill("A");
recursion();
function a1 (){
return true;
}
function a2 (){
switch(arr[1])
{
case "A":
return arr[4] === "C"
case "B":
return arr[4] === "D"
case "C":
return arr[4] === "A"
case "D":
return arr[4] === "B"
default:
return false;
}
}
function a3 (){
switch(arr[2])
{
case "A":
return arr[5] === arr[1] && arr[5] === arr[3]
case "B":
return arr[2] === arr[1] && arr[2] === arr[3]
case "C":
return arr[5] === arr[2] && arr[5] === arr[3]
case "D":
return arr[5] === arr[1] && arr[5] === arr[2]
default:
return false;
}
}
function a4 (){
var f1 = arr[0] === arr[4] ,
f2 = arr[1] === arr[6] ,
f3 = arr[0] === arr[8] ,
f4 = arr[5] === arr[9] ;
switch(arr[3])
{
case "A":
return f1 && !f2 && !f3 && !f4
case "B":
return !f1 && f2 && !f3 && !f4
case "C":
return !f1 && !f2 && f3 && !f4
case "D":
return !f1 && !f2 && !f3 && f4
default:
return false;
}
}
function a5 (){
switch(arr[4])
{
case "A":
return arr[7] === "A"
case "B":
return arr[3] === "B"
case "C":
return arr[8] === "C"
case "D":
return arr[6] === "D"
default:
return false;
}
}
function a6 (){
var f1 = arr[7] === arr[1] && arr[7] === arr[3] ,
f2 = arr[7] === arr[0] && arr[7] === arr[5] ,
f3 = arr[7] === arr[2] && arr[7] === arr[9] ,
f4 = arr[7] === arr[4] && arr[7] === arr[8] ;
switch(arr[5])
{
case "A":
return f1 && !f2 && !f3 && !f4
case "B":
return !f1 && f2 && !f3 && !f4
case "C":
return !f1 && !f2 && f3 && !f4
case "D":
return !f1 && !f2 && !f3 && f4
default:
return false;
}
}
function a7 (){
var c1 = arr.filter((i)=>{return i === "A"}).length ,
c2 = arr.filter((i)=>{return i === "B"}).length ,
c3 = arr.filter((i)=>{return i === "C"}).length ,
c4 = arr.filter((i)=>{return i === "D"}).length ;
switch(arr[6])
{
case "A":
return Math.min(c1,c2,c3,c4) === c3
case "B":
return Math.min(c1,c2,c3,c4) === c2
case "C":
return Math.min(c1,c2,c3,c4) === c1
case "D":
return Math.min(c1,c2,c3,c4) === c4
default:
return false;
}
}
function a8 (){
switch(arr[7])
{
case "A":
return Math.abs(arr[0].charCodeAt(0) - arr[6].charCodeAt(0))>=2
case "B":
return Math.abs(arr[0].charCodeAt(0) - arr[4].charCodeAt(0))>=2
case "C":
return Math.abs(arr[0].charCodeAt(0) - arr[1].charCodeAt(0))>=2
case "D":
return Math.abs(arr[0].charCodeAt(0) - arr[9].charCodeAt(0))>=2
default:
return false;
}
}
function a9 (){
var flag = arr[0] === arr[5],
f1 = (arr[4] === arr[5]) === !flag ,
f2 = (arr[4] === arr[9]) === !flag ,
f3 = (arr[4] === arr[1]) === !flag ,
f4 = (arr[4] === arr[8]) === !flag ;
switch(arr[8])
{
case "A":
return f1 && !f2 && !f3 && !f4
case "B":
return !f1 && f2 && !f3 && !f4
case "C":
return !f1 && !f2 && f3 && !f4
case "D":
return !f1 && !f2 && !f3 && f4
default:
return false;
}
}
function a10 (){
var c1 = arr.filter((i)=>{return i === "A"}).length ,
c2 = arr.filter((i)=>{return i === "B"}).length ,
c3 = arr.filter((i)=>{return i === "C"}).length ,
c4 = arr.filter((i)=>{return i === "D"}).length ;
switch(arr[9])
{
case "A":
return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 3
case "B":
return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 2
case "C":
return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 4
case "D":
return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 1
default:
return false;
}
}
function vali () {
return a1() && a2() && a3() && a4() && a5() && a6() && a7() && a8() && a9() && a10() ;
}
//遞迴遍歷arr的所有排列組合
function recursion (){
if(vali()){
console.log(arr);
}
for(var x=0 ; x<arr.length ; x++){
switch(arr[x])
{
case "A":
arr[x] = "B" ;
recursion () ;
return ;
case "B":
arr[x] = "C"
recursion () ;
return ;
case "C":
arr[x] = "D" ;
recursion () ;
return ;
case "D":
if(x===9) return ;
arr[x] = "A" ;
continue ;
default:
return ;
}
}
}
</script>
複製程式碼
以上的程式碼邏輯上沒有問題,但是還是報了個錯——棧溢位
雖然王二也試著用尾遞迴優化來嘗試解決問題,但依然報錯
三、解決方法
後來王二躺床上又尋思怎麼才能解決這噁心的報錯,然後想到try
catch
可以捕獲錯誤,或許我們能遞迴呼叫 try
catch
來解決這個問題。按照這個思路王二又在程式碼片段中新增了如下的程式碼:
var flag = true ;
function run () {
try {
if(flag){
flag = false ;
recursion() ;
}
} catch (err) {
flag = true;
run();
}
}
複製程式碼
意思是如果棧溢位報錯,則在 catch
再次呼叫 run()
方法 ,直到它不報錯為止,不報錯也就意味著arr
陣列所有排列組合的可能性都被遍歷完了。
執行後,還真他孃的起作用了。
完整的程式碼片段如下所示(可以拷貝下來嘗試執行):
<script>
var arr = new Array(10).fill("A");
var flag = true ;
run(); // ["B", "C", "A", "C", "A", "C", "D", "A", "B", "A"]
function run () {
try {
if(flag){
flag = false ;
recursion() ;
}
} catch (err) {
flag = true;
run();
}
}
function a1 (){
return true;
}
function a2 (){
switch(arr[1])
{
case "A":
return arr[4] === "C"
case "B":
return arr[4] === "D"
case "C":
return arr[4] === "A"
case "D":
return arr[4] === "B"
default:
return false;
}
}
function a3 (){
switch(arr[2])
{
case "A":
return arr[5] === arr[1] && arr[5] === arr[3]
case "B":
return arr[2] === arr[1] && arr[2] === arr[3]
case "C":
return arr[5] === arr[2] && arr[5] === arr[3]
case "D":
return arr[5] === arr[1] && arr[5] === arr[2]
default:
return false;
}
}
function a4 (){
var f1 = arr[0] === arr[4] ,
f2 = arr[1] === arr[6] ,
f3 = arr[0] === arr[8] ,
f4 = arr[5] === arr[9] ;
switch(arr[3])
{
case "A":
return f1 && !f2 && !f3 && !f4
case "B":
return !f1 && f2 && !f3 && !f4
case "C":
return !f1 && !f2 && f3 && !f4
case "D":
return !f1 && !f2 && !f3 && f4
default:
return false;
}
}
function a5 (){
switch(arr[4])
{
case "A":
return arr[7] === "A"
case "B":
return arr[3] === "B"
case "C":
return arr[8] === "C"
case "D":
return arr[6] === "D"
default:
return false;
}
}
function a6 (){
var f1 = arr[7] === arr[1] && arr[7] === arr[3] ,
f2 = arr[7] === arr[0] && arr[7] === arr[5] ,
f3 = arr[7] === arr[2] && arr[7] === arr[9] ,
f4 = arr[7] === arr[4] && arr[7] === arr[8] ;
switch(arr[5])
{
case "A":
return f1 && !f2 && !f3 && !f4
case "B":
return !f1 && f2 && !f3 && !f4
case "C":
return !f1 && !f2 && f3 && !f4
case "D":
return !f1 && !f2 && !f3 && f4
default:
return false;
}
}
function a7 (){
var c1 = arr.filter((i)=>{return i === "A"}).length ,
c2 = arr.filter((i)=>{return i === "B"}).length ,
c3 = arr.filter((i)=>{return i === "C"}).length ,
c4 = arr.filter((i)=>{return i === "D"}).length ;
switch(arr[6])
{
case "A":
return Math.min(c1,c2,c3,c4) === c3
case "B":
return Math.min(c1,c2,c3,c4) === c2
case "C":
return Math.min(c1,c2,c3,c4) === c1
case "D":
return Math.min(c1,c2,c3,c4) === c4
default:
return false;
}
}
function a8 (){
switch(arr[7])
{
case "A":
return Math.abs(arr[0].charCodeAt(0) - arr[6].charCodeAt(0))>=2
case "B":
return Math.abs(arr[0].charCodeAt(0) - arr[4].charCodeAt(0))>=2
case "C":
return Math.abs(arr[0].charCodeAt(0) - arr[1].charCodeAt(0))>=2
case "D":
return Math.abs(arr[0].charCodeAt(0) - arr[9].charCodeAt(0))>=2
default:
return false;
}
}
function a9 (){
var flag = arr[0] === arr[5],
f1 = (arr[4] === arr[5]) === !flag ,
f2 = (arr[4] === arr[9]) === !flag ,
f3 = (arr[4] === arr[1]) === !flag ,
f4 = (arr[4] === arr[8]) === !flag ;
switch(arr[8])
{
case "A":
return f1 && !f2 && !f3 && !f4
case "B":
return !f1 && f2 && !f3 && !f4
case "C":
return !f1 && !f2 && f3 && !f4
case "D":
return !f1 && !f2 && !f3 && f4
default:
return false;
}
}
function a10 (){
var c1 = arr.filter((i)=>{return i === "A"}).length ,
c2 = arr.filter((i)=>{return i === "B"}).length ,
c3 = arr.filter((i)=>{return i === "C"}).length ,
c4 = arr.filter((i)=>{return i === "D"}).length ;
switch(arr[9])
{
case "A":
return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 3
case "B":
return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 2
case "C":
return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 4
case "D":
return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 1
default:
return false;
}
}
function vali () {
return a1() && a2() && a3() && a4() && a5() && a6() && a7() && a8() && a9() && a10() ;
}
//遞迴遍歷arr的所有排列組合
function recursion (){
if(vali()){
console.log(arr);
}
for(var x=0 ; x<arr.length ; x++){
switch(arr[x])
{
case "A":
arr[x] = "B" ;
recursion () ;
return ;
case "B":
arr[x] = "C"
recursion () ;
return ;
case "C":
arr[x] = "D" ;
recursion () ;
return ;
case "D":
if(x===9) return ;
arr[x] = "A" ;
continue ;
default:
return ;
}
}
}
</script>
複製程式碼
這樣的寫話棧溢位的問題似乎就比較完美的被解決了。
2018年04月27日補充:
其實那天晚上王二腦子進水了,其實這裡沒有必要用到遞迴呼叫,現修改程式碼如下:
var arr = new Array(10).fill("A");
while(recursion(arr)!=='done'){
vali() && console.log(arr)
}
function a1 (){
return true;
}
function a2 (){
switch(arr[1])
{
case "A":
return arr[4] === "C"
case "B":
return arr[4] === "D"
case "C":
return arr[4] === "A"
case "D":
return arr[4] === "B"
default:
return false;
}
}
function a3 (){
switch(arr[2])
{
case "A":
return arr[5] === arr[1] && arr[5] === arr[3]
case "B":
return arr[2] === arr[1] && arr[2] === arr[3]
case "C":
return arr[5] === arr[2] && arr[5] === arr[3]
case "D":
return arr[5] === arr[1] && arr[5] === arr[2]
default:
return false;
}
}
function a4 (){
var f1 = arr[0] === arr[4] ,
f2 = arr[1] === arr[6] ,
f3 = arr[0] === arr[8] ,
f4 = arr[5] === arr[9] ;
switch(arr[3])
{
case "A":
return f1 && !f2 && !f3 && !f4
case "B":
return !f1 && f2 && !f3 && !f4
case "C":
return !f1 && !f2 && f3 && !f4
case "D":
return !f1 && !f2 && !f3 && f4
default:
return false;
}
}
function a5 (){
switch(arr[4])
{
case "A":
return arr[7] === "A"
case "B":
return arr[3] === "B"
case "C":
return arr[8] === "C"
case "D":
return arr[6] === "D"
default:
return false;
}
}
function a6 (){
var f1 = arr[7] === arr[1] && arr[7] === arr[3] ,
f2 = arr[7] === arr[0] && arr[7] === arr[5] ,
f3 = arr[7] === arr[2] && arr[7] === arr[9] ,
f4 = arr[7] === arr[4] && arr[7] === arr[8] ;
switch(arr[5])
{
case "A":
return f1 && !f2 && !f3 && !f4
case "B":
return !f1 && f2 && !f3 && !f4
case "C":
return !f1 && !f2 && f3 && !f4
case "D":
return !f1 && !f2 && !f3 && f4
default:
return false;
}
}
function a7 (){
var c1 = arr.filter((i)=>{return i === "A"}).length ,
c2 = arr.filter((i)=>{return i === "B"}).length ,
c3 = arr.filter((i)=>{return i === "C"}).length ,
c4 = arr.filter((i)=>{return i === "D"}).length ;
switch(arr[6])
{
case "A":
return Math.min(c1,c2,c3,c4) === c3
case "B":
return Math.min(c1,c2,c3,c4) === c2
case "C":
return Math.min(c1,c2,c3,c4) === c1
case "D":
return Math.min(c1,c2,c3,c4) === c4
default:
return false;
}
}
function a8 (){
switch(arr[7])
{
case "A":
return Math.abs(arr[0].charCodeAt(0) - arr[6].charCodeAt(0))>=2
case "B":
return Math.abs(arr[0].charCodeAt(0) - arr[4].charCodeAt(0))>=2
case "C":
return Math.abs(arr[0].charCodeAt(0) - arr[1].charCodeAt(0))>=2
case "D":
return Math.abs(arr[0].charCodeAt(0) - arr[9].charCodeAt(0))>=2
default:
return false;
}
}
function a9 (){
var flag = arr[0] === arr[5],
f1 = (arr[4] === arr[5]) === !flag ,
f2 = (arr[4] === arr[9]) === !flag ,
f3 = (arr[4] === arr[1]) === !flag ,
f4 = (arr[4] === arr[8]) === !flag ;
switch(arr[8])
{
case "A":
return f1 && !f2 && !f3 && !f4
case "B":
return !f1 && f2 && !f3 && !f4
case "C":
return !f1 && !f2 && f3 && !f4
case "D":
return !f1 && !f2 && !f3 && f4
default:
return false;
}
}
function a10 (){
var c1 = arr.filter((i)=>{return i === "A"}).length ,
c2 = arr.filter((i)=>{return i === "B"}).length ,
c3 = arr.filter((i)=>{return i === "C"}).length ,
c4 = arr.filter((i)=>{return i === "D"}).length ;
switch(arr[9])
{
case "A":
return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 3
case "B":
return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 2
case "C":
return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 4
case "D":
return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 1
default:
return false;
}
}
function vali () {
return a1() && a2() && a3() && a4() && a5() && a6() && a7() && a8() && a9() && a10() ;
}
function recursion(arr){
for(var x=0 ; x<arr.length ; x++){
switch(arr[x])
{
case "A":
arr[x] = "B" ;
return arr;
case "B":
arr[x] = "C"
return arr;
case "C":
arr[x] = "D" ;
return arr;
case "D":
if(x===9) return 'done';
arr[x] = "A" ;
continue ;
default:
return 'error';
}
}
}
複製程式碼
如此簡單的問題王二那天想的那麼複雜,也是醉了。
原文地址:王玉略的個人網站