请问这两种写法为什么结果不一样? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
n0bug
V2EX    问与答

请问这两种写法为什么结果不一样?

  •  
      n0bug 2024-11-07 16:58:55 +08:00 1652 次点击
    这是一个创建于 406 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在刷题,有一段代码如果写成下面这样结果就是对的

    func foo(i, j int) bool { ret1 := foo(i+1, j) ret2 := foo(i-1, j) ret3 := foo(i, j+1) ret4 := foo(i, j-1) return ret1 && ret2 && ret3 && ret4 } 

    但是如果写成这样,某些 test case 结果就错

    func foo(i, j int) bool { return foo(i+1, j) && foo(i-1, j) && foo(i, j+1) && foo(i, j-1) } 

    想不明白啊,这两种写法哪里不一样了?

    第 1 条附言    2024-11-07 17:38:23 +08:00

    回答二楼的问题,foo() 函数里面会改变一些值,我写上更加完整的吧,

    func foo(g [][]int, v [][]bool, i, j int) bool { ret1 := foo(g, v, i+1, j) ret2 := foo(g, v, , i-1, j) ret3 := foo(g, v, i, j+1) ret4 := foo(g, v, i, j-1) return ret1 && ret2 && ret3 && ret4 } 
    func foo(g [][]int, v [][]bool, i, j int) bool { return foo(g, v, i+1, j) && foo(g, v, i-1, j) && foo(g, v, i, j+1) && foo(g,v, i, j-1) } 

    执行过程中会对 v[i][j] 的值进行修改

    7 条回复    2024-11-07 19:14:35 +08:00
    pweng286
        1
    pweng286  
       2024-11-07 17:01:01 +08:00
    AI
    关键区别:
    递归调用顺序:

    在第一段代码中,foo 被分别递归调用并赋值给 ret1, ret2, ret3, ret4 。这意味着所有的递归调用会 按顺序 执行,一个接一个。如果在某个递归过程中返回了 false ,其余的递归调用仍然会继续执行,但最终的返回值是 ret1 && ret2 && ret3 && ret4 ,即它会检查所有递归的结果。

    在第二段代码中,所有的递归调用都在 一个单一的布尔表达式中同时执行。这意味着 foo(i+1, j) && foo(i-1, j) && foo(i, j+1) && foo(i, j-1) 会在一开始就 并行执行(实际上是按照顺序依赖 && 操作符的短路性质)。短路运算意味着如果第一个调用(例如 foo(i+1, j))返回 false ,那么剩下的递归调用会被 立即跳过,并且整个表达式会立刻返回 false ,不会继续执行其他递归调用。

    短路特性:

    在第二段代码中,&& 是一个短路操作符,也就是说,当第一个 foo(i+1, j) 返回 false 时,后续的 foo(i-1, j), foo(i, j+1), foo(i, j-1) 会 被跳过,因此可能会导致在某些情况下,代码没有完整地执行所有递归调用,可能会错过一些重要的逻辑判断。

    而在第一段代码中,由于每个递归调用是逐个进行的,即使某些调用的返回值是 false ,后续的递归调用仍会被执行,所以你可以确保每次递归的每一个方向都被检查。

    为什么第二种写法会错误:
    如果你的递归逻辑依赖于每个方向( i+1, i-1, j+1, j-1 )的返回值,那么在第二段代码中,短路机制 可能导致部分方向没有被检查到。例如:

    假设 foo(i+1, j) 返回 false ,根据短路原则,后面的 foo(i-1, j)、foo(i, j+1)、foo(i, j-1) 就不会执行了。因此,可能漏掉了一些重要的判断,导致最终结果不正确。
    而在第一种写法中,虽然某个方向可能返回 false ,但是所有的递归都会执行,确保每个方向都被遍历,从而保证递归的正确性。

    总结:
    第一段代码按顺序递归调用每个方向,确保所有的递归都被执行,因此不会错过任何重要的检查。
    第二段代码在使用短路操作符时,一旦某个递归返回 false ,后续的递归就不会继续进行,可能导致遗漏重要的判断逻辑,从而造成错误。
    因此,如果你的递归逻辑需要检查所有的方向,那么你应该使用第一种写法,逐个递归调用每个方向。
    CEBBCAT
        2
    CEBBCAT  
       2024-11-07 17:03:26 +08:00
    内嵌的那个 foo 有状态吗?
    n0bug
        3
    n0bug  
    OP
       2024-11-07 17:38:39 +08:00
    @CEBBCAT 会的,我更新了一下问题
    CSM
        4
    CSM  
       2024-11-07 17:42:31 +08:00
    zapper
        5
    zapper  
       2024-11-07 17:50:05 +08:00
    @pweng286 #1 请不要把 AI 生成的内容发送到这里
    about
    sqfphoenix
        6
    sqfphoenix  
       2024-11-07 18:00:39 +08:00
    第二种写法前面某一个 foo 返回 false 了,之后的 foo 都不会执行了
    pweng286
        7
    pweng286  
       2024-11-07 19:14:35 +08:00
    @zapper 好的
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2901 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 21ms UTC 14:04 PVG 22:04 LAX 06:04 JFK 09:04
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86