为何在有效字母异位词解法中foreach循环比for循环更快?
为什么两次foreach遍历的解法比单次for循环更快?
我用下面的解法完成了LeetCode的**有效字母异位词(Valid Anagram)**问题,运行时长为4ms:
class Solution { public boolean isAnagram(String s, String t) { if (s.length() != t.length()) { return false; } int[] countArray = new int[26]; char[] a = s.toCharArray(); char[] b = t.toCharArray(); for (int i = 0; i < s.length(); i++) { countArray[a[i] - 'a']++; countArray[b[i] - 'a']--; } for (int i = 0; i < 26; i++) { if (countArray[i] != 0) { return false; } } return true; } }
但我看到有人使用foreach循环的解法仅耗时2ms:
class Solution { public boolean isAnagram(String s, String t) { if (s.length() != t.length()) { return false; } int[] countArray = new int[26]; for (char ch : s.toCharArray()) { countArray[ch - 'a']++; } for (char ch : t.toCharArray()) { countArray[ch - 'a']--; } for (int count : countArray) { if (count != 0) { return false; } } return true; } }
关键原因分析
缓存局部性优势
你的解法在单次循环中交替访问两个独立的char数组a和b,这种跨数组的随机访问会降低CPU缓存(L1/L2)的命中率——缓存更擅长处理连续内存地址的访问。而foreach解法是先连续遍历完第一个字符串的char数组,再连续遍历第二个,整个过程内存访问是连续的,缓存能高效命中,减少CPU等待内存数据的时间,整体执行速度更快。JVM对foreach的编译优化
Java中遍历数组的foreach循环会被编译器直接优化为高效的下标遍历,而且JVM的即时编译器(JIT)更容易对这种连续的单数组遍历做进一步优化,比如循环展开、指令重排,减少循环的额外开销。相比之下,你的手动for循环虽然逻辑上少一次遍历,但交替访问两个数组的操作让JVM难以做针对性优化。计时结果的参考性
另外要注意,LeetCode的单次计时可能受服务器负载、JVM预热等因素影响存在误差,但如果多次测试都呈现foreach更快的结果,上面的缓存和编译优化就是核心原因。
内容的提问来源于stack exchange,提问作者kanoonsantikul
相关产品推荐
相关产品推荐

