From 5fd04305ee680cb906d1e04184e031042b4f7973 Mon Sep 17 00:00:00 2001 From: Sidney Zhang Date: Tue, 6 Jan 2026 14:30:51 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(Palindromes)=EF=BC=9A=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=AC=A7=E6=8B=89=E9=A1=B9=E7=9B=AE=E7=AC=AC36?= =?UTF-8?q?=E9=A2=98=E8=A7=A3=E5=86=B3=E6=96=B9=E6=A1=88=20=F0=9F=93=9D=20?= =?UTF-8?q?docs(Palindromes)=EF=BC=9A=E5=88=9B=E5=BB=BAREADME=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E8=AF=B4=E6=98=8E=E6=80=A7=E8=83=BD=E5=AF=B9=E6=AF=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- solutions/0036.Palindromes/euler_36.hs | 110 +++++++++++++++++++++++++ solutions/0036.Palindromes/readme.md | 13 +++ 2 files changed, 123 insertions(+) create mode 100644 solutions/0036.Palindromes/euler_36.hs create mode 100644 solutions/0036.Palindromes/readme.md diff --git a/solutions/0036.Palindromes/euler_36.hs b/solutions/0036.Palindromes/euler_36.hs new file mode 100644 index 0000000..3e8cbd1 --- /dev/null +++ b/solutions/0036.Palindromes/euler_36.hs @@ -0,0 +1,110 @@ +{-# LANGUAGE BangPatterns #-} + +import Data.Time (diffUTCTime, getCurrentTime) +import Text.Printf (printf) +import Data.Bits (shiftR, testBit, setBit) +import Control.DeepSeq (force, NFData) +import Control.Exception (evaluate) + +-- 计时函数 +time :: NFData a => String -> IO a -> IO a +time label action = do + start <- getCurrentTime + result <- action + result' <- evaluate (force result) + end <- getCurrentTime + printf "%s took time: %.6f seconds\n" label (realToFrac (diffUTCTime end start) :: Double) + return result' + +-- 反转十进制数字(辅助函数) +reverseDecimal :: Integer -> Integer +reverseDecimal = go 0 + where + go acc 0 = acc + go acc x = let (q, r) = quotRem x 10 + in go (acc * 10 + r) q + +-- 十进制回文检查 +isDecimalPalindromic :: Integer -> Bool +isDecimalPalindromic n = n == reverseDecimal n + +-- 二进制回文检查(使用位运算) +isBinaryPalindromic :: Integer -> Bool +isBinaryPalindromic n + | n < 0 = False + | otherwise = n == reverseBinary n + where + -- 计算二进制位数 + bitLength :: Integer -> Int + bitLength 0 = 1 + bitLength x = go 0 x + where + go !len 0 = len + go !len y = go (len + 1) (y `shiftR` 1) + + -- 反转二进制位 + reverseBinary :: Integer -> Integer + reverseBinary x = go 0 (bitLength x) x + where + go !acc 0 _ = acc + go !acc !len y + | testBit y 0 = go (acc `setBit` (len - 1)) (len - 1) (y `shiftR` 1) + | otherwise = go acc (len - 1) (y `shiftR` 1) + +-- 简单方法:遍历所有数字 +mainSimple :: Integer -> IO () +mainSimple limit = do + let nums = [0..limit] + palindromes = filter (\n -> isDecimalPalindromic n && isBinaryPalindromic n) nums + result = sum palindromes + print result + +-- 生成指定长度的十进制回文数(优化版) +palindromesOfLength :: Int -> [Integer] +palindromesOfLength 1 = [0..9] +palindromesOfLength len + | even len = buildPalindromes evenPalindrome halfRange + | otherwise = buildPalindromes oddPalindrome halfRange + where + halfLen = (len + 1) `div` 2 + start = 10^(halfLen-1) + end = 10^halfLen - 1 + halfRange = [start..end] + + buildPalindromes :: (Integer -> Integer) -> [Integer] -> [Integer] + buildPalindromes f = map f + + evenPalindrome :: Integer -> Integer + evenPalindrome half = + let s = half + reversed = reverseDecimal s + shift = 10^halfLen + in s * shift + reversed + + oddPalindrome :: Integer -> Integer + oddPalindrome half = + let s = half + power = halfLen - 1 + shift = 10^power + reversed = reverseDecimal (s `quot` 10) + in s * shift + reversed + +-- 快速方法:生成回文数而非遍历 +mainQuick :: Integer -> IO () +mainQuick limit = do + let maxLength = length (show (limit - 1)) + -- 限制每个长度生成的回文数不超过limit + limitedPalindromes = takeWhile (<= limit) $ concatMap palindromesOfLength [1..maxLength] + validPalindromes = filter isBinaryPalindromic limitedPalindromes + result = sum validPalindromes + print result + +-- 主函数 +main :: IO () +main = do + let limit = 1000000 + putStrLn "=== mainSimple (朴素遍历法) ===" + time "mainSimple" $ mainSimple limit + + putStrLn "\n=== mainQuick (回文数生成法) ===" + time "mainQuick" $ mainQuick limit diff --git a/solutions/0036.Palindromes/readme.md b/solutions/0036.Palindromes/readme.md new file mode 100644 index 0000000..a77ccd5 --- /dev/null +++ b/solutions/0036.Palindromes/readme.md @@ -0,0 +1,13 @@ +# README + +说起来,还是先找到所有回文数字更快,单纯计算查找确实稍慢。 +另外,就是python3.13比haskell还要快一线……我也是囧了…… + + + +**haskell** + +```bash +> ghc euler_36.hs +> ./euler_36.exe +```