[英]Longest Palindrome Edge Case due to String / StringBuilder Equality
此代碼不適用於測試用例: aacabdkacaa
,但適用於babad
或cbbd
。 我寫了一個打印語句來調試並意識到代碼認為字符串aacakdbacaa
和aacabdkacaa
出於某種原因是等價的。 他們顯然不是,所以我錯過了什么?
class Solution {
public String longestPalindrome(String s) {
String longPal = "";
for(int i = 0; i < s.length(); i++) {
for(int j = s.length()-1; j >= i; j--) {
if(s.charAt(i) == s.charAt(j)) {
StringBuilder sb = new StringBuilder(s.substring(i, j+1));
if(sb.reverse().toString().equals(sb.toString())
&& sb.toString().length() > longPal.length()) {
longPal = sb.toString();
System.out.println(sb.toString()+" equals "+sb.reverse().toString());
}
sb.setLength(0);
}
}
}
return longPal;
}
}
代碼不認為aacakdbacaa
和aacabdkacaa
是相等的。
if
語句中條件的第一部分是 this
sb.reverse().toString().equals(sb.toString())
所以代碼(JVM)認為這個條件是true
。 這是為什么? 這背后隱藏着什么知識(因為有一些)?
隱藏的知識部分(並不是真正隱藏,在文檔中)是StringBuilder reverse
方法(實際上幾乎所有SB方法)改變了StringBuilder的state,通常返回StringBuilder實例本身。
所以對sb.reverse()
的調用只是反轉 StringBuilder 實例的內容並返回實例本身(即相同的實例。),實例沒有改變。 只是它的內部 state 發生了變化。
然后我們對其調用toString()
,它返回當前 state 的String
表示(如預期的那樣)。
然后我們在返回的String
上調用equals
並傳入equals
sb.toString()
作為第一個參數的值。 但是sb
與一納秒前從sb.reverse()
返回的實例相同。 它的 state 之間沒有改變,所以我們得到了從調用sb.toString()
返回的相同String
表示。
這就是為什么
sb.reverse().toString().equals(sb.toString())
是真的。
我們可以稍微不同地寫它,但仍然得到相同的結果
String s1 = sb.reverse().toString() // sb state changed here when .reverse() was called
String s2 = sb.toString()
s1.equals(s2) // true
如果我們使用,我們會得到不同的結果
String s1 = sb.toString()
String s2 = sb.reverse().toString() // sb state changed here
s1.equals(s2) // now it depends, true if palindrome, false otherwise!
所以這將是檢查回文的正確檢查
sb.toString().equals(sb.reverse().toString())
StringBuilder 的 reverse() 方法導致它的字符序列被序列的反向替換,因此 sb.reverse().toString().equals(sb.toString()) 總是結果為真。 聲明另一個字符串String p = sb.toString()
然后用它來比較sb.reverse().toString().equals(p.toString())
可以解決問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.