Problem

You are given a hexadecimal-encoded string that has been XOR’d against a single char.

Decrypt the message. For example, given the string:

1
7a575e5e5d12455d405e561254405d5f1276535b5e4b12715d565b5c551262405d505e575f

You should be able to decrypt it and get:

1
Hello world from Daily Coding Problem

Examples

Example 1

1
2
3
Input: "7a575e5e5d12455d405e561254405d5f1276535b5e4b12715d565b5c551262405d505e575f"
Output: "Hello world from Daily Coding Problem"
Explanation: The hex string is XOR'd with key 0x32 ('2'). Decrypting each byte: 0x7a^0x32=0x48('H'), 0x57^0x32=0x65('e'), etc.

Example 2

1
2
3
Input: "0d1c1b1b15461f1b0c1e14460c1b14461511071b171546050f1718"
Output: "Hello world from me"
Explanation: The hex string is XOR'd with key 0x69 ('i'). Each hex pair XOR'd with 0x69 produces ASCII characters.

Example 3

1
2
3
Input: "2b0a0f0f15641815040a1f64041519642b1a071564341c1a0a0b1b"
Output: "Hello world from DCP"
Explanation: XOR key is 0x67 ('g'). Decryption reveals the hidden message.

Example 4

1
2
3
Input: "565d525252284b52435d5128435229285647405248285c41525d5a50"
Output: "Hello world from XOR"
Explanation: Single character XOR with key 0x3a (':') produces the plaintext message.

Example 5

1
2
3
Input: "48656c6c6f"
Output: "Hello"
Explanation: Simple case - hex string "Hello" is not XOR'd (key = 0x00), direct hex-to-ASCII conversion.

Example 6

1
2
3
Input: ""
Output: ""
Explanation: Empty input produces empty output.

Solution

Intuition

Since XOR encryption with a single character key has only 256 possible keys (0x00 to 0xFF), we can try all possible keys and evaluate which one produces the most readable English text. The correct key will produce text with common English characters, spaces, and recognizable patterns. We can score each attempt based on frequency of common English characters and choose the highest-scoring result.

Approach

  1. Convert Hex to Bytes: Parse the hexadecimal string into an array of bytes
  2. Handle Edge Cases: Return empty string for empty input
  3. Try All Keys: Iterate through all 256 possible XOR keys (0x00 to 0xFF)
  4. XOR Decryption: For each key, XOR every byte with the key to get potential plaintext
  5. Score Results: Evaluate each result based on English text characteristics:
    • Count printable ASCII characters (32-126)
    • Give higher scores to common letters and spaces
    • Penalize non-printable or unusual characters
  6. Select Best: Choose the decryption with the highest score
  7. Return Result: Convert the best byte array back to string

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class Solution {
public:
    string decryptXOR(string hexStr) {
        if (hexStr.empty()) return "";
        
        // Convert hex string to bytes
        vector<uint8_t> bytes = hexToBytes(hexStr);
        if (bytes.empty()) return "";
        
        string bestResult = "";
        int bestScore = -1;
        
        // Try all possible XOR keys
        for (int key = 0; key < 256; key++) {
            string candidate = tryKey(bytes, key);
            int score = scoreText(candidate);
            
            if (score > bestScore) {
                bestScore = score;
                bestResult = candidate;
            }
        }
        
        return bestResult;
    }
    
private:
    vector<uint8_t> hexToBytes(string hex) {
        vector<uint8_t> bytes;
        for (int i = 0; i < hex.length(); i += 2) {
            if (i + 1 < hex.length()) {
                string hexPair = hex.substr(i, 2);
                bytes.push_back(stoi(hexPair, nullptr, 16));
            }
        }
        return bytes;
    }
    
    string tryKey(const vector<uint8_t>& bytes, int key) {
        string result = "";
        for (uint8_t byte : bytes) {
            result += char(byte ^ key);
        }
        return result;
    }
    
    int scoreText(const string& text) {
        int score = 0;
        for (char c : text) {
            if (c >= 32 && c <= 126) { // Printable ASCII
                score += 2;
                if (c == ' ') score += 3; // Space bonus
                else if (isalpha(c)) score += 2; // Letter bonus
                else if (isdigit(c)) score += 1; // Digit bonus
            } else {
                score -= 5; // Penalty for non-printable
            }
        }
        return score;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
func DecryptXOR(hexStr string) string {
    if len(hexStr) == 0 {
        return ""
    }
    
    // Convert hex to bytes
    bytes := hexToBytes(hexStr)
    if len(bytes) == 0 {
        return ""
    }
    
    bestResult := ""
    bestScore := -1
    
    // Try all possible keys
    for key := 0; key < 256; key++ {
        candidate := tryKey(bytes, byte(key))
        score := scoreText(candidate)
        
        if score > bestScore {
            bestScore = score
            bestResult = candidate
        }
    }
    
    return bestResult
}

func hexToBytes(hex string) []byte {
    var bytes []byte
    for i := 0; i < len(hex); i += 2 {
        if i+1 < len(hex) {
            val, err := strconv.ParseUint(hex[i:i+2], 16, 8)
            if err == nil {
                bytes = append(bytes, byte(val))
            }
        }
    }
    return bytes
}

func tryKey(bytes []byte, key byte) string {
    var result strings.Builder
    for _, b := range bytes {
        result.WriteByte(b ^ key)
    }
    return result.String()
}

func scoreText(text string) int {
    score := 0
    for _, c := range text {
        if c >= 32 && c <= 126 { // Printable ASCII
            score += 2
            if c == ' ' {
                score += 3 // Space bonus
            } else if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') {
                score += 2 // Letter bonus
            } else if c >= '0' && c <= '9' {
                score += 1 // Digit bonus
            }
        } else {
            score -= 5 // Penalty
        }
    }
    return score
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
class Solution {
    public String decryptXOR(String hexStr) {
        if (hexStr.isEmpty()) return "";
        
        // Convert hex to bytes
        byte[] bytes = hexToBytes(hexStr);
        if (bytes.length == 0) return "";
        
        String bestResult = "";
        int bestScore = -1;
        
        // Try all possible keys
        for (int key = 0; key < 256; key++) {
            String candidate = tryKey(bytes, (byte)key);
            int score = scoreText(candidate);
            
            if (score > bestScore) {
                bestScore = score;
                bestResult = candidate;
            }
        }
        
        return bestResult;
    }
    
    private byte[] hexToBytes(String hex) {
        List<Byte> byteList = new ArrayList<>();
        for (int i = 0; i < hex.length(); i += 2) {
            if (i + 1 < hex.length()) {
                String hexPair = hex.substring(i, i + 2);
                try {
                    byteList.add((byte)Integer.parseInt(hexPair, 16));
                } catch (NumberFormatException e) {
                    // Skip invalid hex pairs
                }
            }
        }
        
        byte[] bytes = new byte[byteList.size()];
        for (int i = 0; i < byteList.size(); i++) {
            bytes[i] = byteList.get(i);
        }
        return bytes;
    }
    
    private String tryKey(byte[] bytes, byte key) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append((char)(b ^ key));
        }
        return result.toString();
    }
    
    private int scoreText(String text) {
        int score = 0;
        for (char c : text.toCharArray()) {
            if (c >= 32 && c <= 126) { // Printable ASCII
                score += 2;
                if (c == ' ') score += 3; // Space bonus
                else if (Character.isLetter(c)) score += 2; // Letter bonus
                else if (Character.isDigit(c)) score += 1; // Digit bonus
            } else {
                score -= 5; // Penalty for non-printable
            }
        }
        return score;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class Solution:
    def decryptXOR(self, hex_str: str) -> str:
        if not hex_str:
            return ""
        
        # Convert hex to bytes
        bytes_data = self._hexToBytes(hex_str)
        if not bytes_data:
            return ""
        
        best_result = ""
        best_score = -1
        
        # Try all possible keys
        for key in range(256):
            candidate = self._tryKey(bytes_data, key)
            score = self._scoreText(candidate)
            
            if score > best_score:
                best_score = score
                best_result = candidate
        
        return best_result
    
    def _hexToBytes(self, hex_str: str) -> List[int]:
        bytes_data = []
        for i in range(0, len(hex_str), 2):
            if i + 1 < len(hex_str):
                try:
                    hex_pair = hex_str[i:i+2]
                    bytes_data.append(int(hex_pair, 16))
                except ValueError:
                    continue
        return bytes_data
    
    def _tryKey(self, bytes_data: List[int], key: int) -> str:
        result = ""
        for byte_val in bytes_data:
            result += chr(byte_val ^ key)
        return result
    
    def _scoreText(self, text: str) -> int:
        score = 0
        for c in text:
            ascii_val = ord(c)
            if 32 <= ascii_val <= 126:  # Printable ASCII
                score += 2
                if c == ' ':
                    score += 3  # Space bonus
                elif c.isalpha():
                    score += 2  # Letter bonus
                elif c.isdigit():
                    score += 1  # Digit bonus
            else:
                score -= 5  # Penalty for non-printable
        return score

Complexity

  • ⏰ Time complexity: O(n) where n is the length of the hex string, as we try 256 keys (constant) and each key requires O(n) operations to decrypt and score.
  • 🧺 Space complexity: O(n) for storing the byte array and candidate strings during decryption attempts.

Method 2 - Frequency Analysis Optimization

Intuition

We can optimize the brute force approach by using more sophisticated frequency analysis. Instead of just scoring based on printable characters, we can analyze character frequency patterns that match typical English text. This includes checking for common English words, letter frequency distributions, and specific patterns like spaces after common words.

Approach

  1. Enhanced Scoring: Use statistical analysis of English text patterns
  2. Word Detection: Look for common English words in the decrypted text
  3. Character Frequency: Analyze letter frequency against expected English distributions
  4. Pattern Recognition: Detect typical English text patterns (capitalization, punctuation)
  5. Early Termination: Stop searching if we find a very high-confidence result
  6. Multiple Metrics: Combine different scoring methods for better accuracy
  7. Validation: Verify results contain mostly readable English text

Code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
class Solution {
public:
    string decryptXORAdvanced(string hexStr) {
        if (hexStr.empty()) return "";
        
        vector<uint8_t> bytes = hexToBytes(hexStr);
        if (bytes.empty()) return "";
        
        string bestResult = "";
        double bestScore = -1000.0;
        
        for (int key = 0; key < 256; key++) {
            string candidate = tryKey(bytes, key);
            double score = advancedScore(candidate);
            
            if (score > bestScore) {
                bestScore = score;
                bestResult = candidate;
                
                // Early termination for very high confidence
                if (score > 50.0 && isLikelyEnglish(candidate)) {
                    break;
                }
            }
        }
        
        return bestResult;
    }
    
private:
    vector<uint8_t> hexToBytes(string hex) {
        vector<uint8_t> bytes;
        for (int i = 0; i < hex.length(); i += 2) {
            if (i + 1 < hex.length()) {
                string hexPair = hex.substr(i, 2);
                bytes.push_back(stoi(hexPair, nullptr, 16));
            }
        }
        return bytes;
    }
    
    string tryKey(const vector<uint8_t>& bytes, int key) {
        string result = "";
        for (uint8_t byte : bytes) {
            result += char(byte ^ key);
        }
        return result;
    }
    
    double advancedScore(const string& text) {
        double score = 0.0;
        
        // Basic printability score
        int printable = 0, total = text.length();
        for (char c : text) {
            if (c >= 32 && c <= 126) printable++;
        }
        score += (double)printable / total * 20.0;
        
        // Common word bonus
        vector<string> commonWords = {"the", "and", "for", "are", "but", "not", "you", "all", "can", "had", "her", "was", "one", "our", "out", "day", "get", "has", "him", "his", "how", "man", "new", "now", "old", "see", "two", "way", "who", "boy", "did", "its", "let", "put", "say", "she", "too", "use"};
        for (const string& word : commonWords) {
            if (text.find(" " + word + " ") != string::npos || 
                text.find(word + " ") == 0 ||
                text.find(" " + word) == text.length() - word.length() - 1) {
                score += 3.0;
            }
        }
        
        // Character frequency analysis
        vector<double> englishFreq = {8.12, 1.49, 2.78, 4.25, 12.02, 2.23, 2.02, 6.09, 6.97, 0.15, 0.77, 4.03, 2.41, 6.75, 7.51, 1.93, 0.10, 5.99, 6.33, 9.06, 2.76, 0.98, 2.36, 0.15, 1.97, 0.07};
        vector<int> letterCount(26, 0);
        int totalLetters = 0;
        
        for (char c : text) {
            if (isalpha(c)) {
                letterCount[tolower(c) - 'a']++;
                totalLetters++;
            }
        }
        
        if (totalLetters > 0) {
            double freqScore = 0.0;
            for (int i = 0; i < 26; i++) {
                double observed = (double)letterCount[i] / totalLetters * 100.0;
                double expected = englishFreq[i];
                freqScore -= abs(observed - expected) * 0.1;
            }
            score += freqScore;
        }
        
        return score;
    }
    
    bool isLikelyEnglish(const string& text) {
        int spaces = 0, letters = 0, others = 0;
        for (char c : text) {
            if (c == ' ') spaces++;
            else if (isalpha(c)) letters++;
            else if (c >= 32 && c <= 126) others++;
        }
        
        return letters > text.length() * 0.6 && spaces > 0;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
func DecryptXORAdvanced(hexStr string) string {
    if len(hexStr) == 0 {
        return ""
    }
    
    bytes := hexToBytes(hexStr)
    if len(bytes) == 0 {
        return ""
    }
    
    bestResult := ""
    bestScore := -1000.0
    
    for key := 0; key < 256; key++ {
        candidate := tryKey(bytes, byte(key))
        score := advancedScore(candidate)
        
        if score > bestScore {
            bestScore = score
            bestResult = candidate
            
            if score > 50.0 && isLikelyEnglish(candidate) {
                break
            }
        }
    }
    
    return bestResult
}

func advancedScore(text string) float64 {
    score := 0.0
    
    // Printability score
    printable := 0
    for _, c := range text {
        if c >= 32 && c <= 126 {
            printable++
        }
    }
    score += float64(printable) / float64(len(text)) * 20.0
    
    // Common words bonus
    commonWords := []string{"the", "and", "for", "are", "but", "not", "you", "all", "can", "had", "her", "was", "one", "our", "out", "day", "get", "has", "him", "his", "how", "man", "new", "now", "old", "see", "two", "way", "who", "boy", "did", "its", "let", "put", "say", "she", "too", "use"}
    
    for _, word := range commonWords {
        if strings.Contains(text, " "+word+" ") ||
           strings.HasPrefix(text, word+" ") ||
           strings.HasSuffix(text, " "+word) {
            score += 3.0
        }
    }
    
    // Basic frequency analysis
    letterCount := make([]int, 26)
    totalLetters := 0
    
    for _, c := range strings.ToLower(text) {
        if c >= 'a' && c <= 'z' {
            letterCount[c-'a']++
            totalLetters++
        }
    }
    
    if totalLetters > 0 {
        // Simplified frequency scoring
        if letterCount['e'-'a'] > totalLetters/10 { // 'e' is most common
            score += 2.0
        }
        if letterCount['t'-'a'] > totalLetters/15 { // 't' is also common
            score += 1.0
        }
    }
    
    return score
}

func isLikelyEnglish(text string) bool {
    spaces, letters, total := 0, 0, len(text)
    for _, c := range text {
        if c == ' ' {
            spaces++
        } else if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') {
            letters++
        }
    }
    
    return letters > total*6/10 && spaces > 0
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
class Solution {
    public String decryptXORAdvanced(String hexStr) {
        if (hexStr.isEmpty()) return "";
        
        byte[] bytes = hexToBytes(hexStr);
        if (bytes.length == 0) return "";
        
        String bestResult = "";
        double bestScore = -1000.0;
        
        for (int key = 0; key < 256; key++) {
            String candidate = tryKey(bytes, (byte)key);
            double score = advancedScore(candidate);
            
            if (score > bestScore) {
                bestScore = score;
                bestResult = candidate;
                
                if (score > 50.0 && isLikelyEnglish(candidate)) {
                    break;
                }
            }
        }
        
        return bestResult;
    }
    
    private double advancedScore(String text) {
        double score = 0.0;
        
        // Printability score
        long printable = text.chars().filter(c -> c >= 32 && c <= 126).count();
        score += (double)printable / text.length() * 20.0;
        
        // Common words
        String[] commonWords = {"the", "and", "for", "are", "but", "not", "you", "all", "can", "had", "her", "was", "one", "our", "out", "day", "get", "has", "him", "his", "how", "man", "new", "now", "old", "see", "two", "way", "who", "boy", "did", "its", "let", "put", "say", "she", "too", "use"};
        
        for (String word : commonWords) {
            if (text.contains(" " + word + " ") ||
                text.startsWith(word + " ") ||
                text.endsWith(" " + word)) {
                score += 3.0;
            }
        }
        
        // Letter frequency
        int[] letterCount = new int[26];
        int totalLetters = 0;
        
        for (char c : text.toLowerCase().toCharArray()) {
            if (Character.isLetter(c)) {
                letterCount[c - 'a']++;
                totalLetters++;
            }
        }
        
        if (totalLetters > 0) {
            if (letterCount['e' - 'a'] > totalLetters / 10) score += 2.0;
            if (letterCount['t' - 'a'] > totalLetters / 15) score += 1.0;
        }
        
        return score;
    }
    
    private boolean isLikelyEnglish(String text) {
        long spaces = text.chars().filter(c -> c == ' ').count();
        long letters = text.chars().filter(Character::isLetter).count();
        
        return letters > text.length() * 0.6 && spaces > 0;
    }
    
    private byte[] hexToBytes(String hex) {
        List<Byte> byteList = new ArrayList<>();
        for (int i = 0; i < hex.length(); i += 2) {
            if (i + 1 < hex.length()) {
                try {
                    byteList.add((byte)Integer.parseInt(hex.substring(i, i + 2), 16));
                } catch (NumberFormatException e) {
                    // Skip invalid hex
                }
            }
        }
        return byteList.stream().mapToInt(Byte::intValue).collect(ArrayList::new, (list, i) -> list.add((byte)i), ArrayList::addAll).stream().mapToInt(Byte::intValue).toArray();
    }
    
    private String tryKey(byte[] bytes, byte key) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append((char)(b ^ key));
        }
        return result.toString();
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
class Solution:
    def decryptXORAdvanced(self, hex_str: str) -> str:
        if not hex_str:
            return ""
        
        bytes_data = self._hexToBytes(hex_str)
        if not bytes_data:
            return ""
        
        best_result = ""
        best_score = -1000.0
        
        for key in range(256):
            candidate = self._tryKey(bytes_data, key)
            score = self._advancedScore(candidate)
            
            if score > best_score:
                best_score = score
                best_result = candidate
                
                # Early termination for high confidence
                if score > 50.0 and self._isLikelyEnglish(candidate):
                    break
        
        return best_result
    
    def _advancedScore(self, text: str) -> float:
        score = 0.0
        
        # Printability score
        printable = sum(1 for c in text if 32 <= ord(c) <= 126)
        score += (printable / len(text)) * 20.0 if text else 0
        
        # Common words bonus
        common_words = ["the", "and", "for", "are", "but", "not", "you", "all", 
                       "can", "had", "her", "was", "one", "our", "out", "day", 
                       "get", "has", "him", "his", "how", "man", "new", "now", 
                       "old", "see", "two", "way", "who", "boy", "did", "its", 
                       "let", "put", "say", "she", "too", "use"]
        
        text_lower = text.lower()
        for word in common_words:
            if f" {word} " in text_lower or text_lower.startswith(f"{word} ") or text_lower.endswith(f" {word}"):
                score += 3.0
        
        # Enhanced character frequency analysis
        english_freq = [8.12, 1.49, 2.78, 4.25, 12.02, 2.23, 2.02, 6.09, 6.97, 
                       0.15, 0.77, 4.03, 2.41, 6.75, 7.51, 1.93, 0.10, 5.99, 
                       6.33, 9.06, 2.76, 0.98, 2.36, 0.15, 1.97, 0.07]
        
        letter_count = [0] * 26
        total_letters = 0
        
        for c in text.lower():
            if c.isalpha():
                letter_count[ord(c) - ord('a')] += 1
                total_letters += 1
        
        if total_letters > 0:
            freq_score = 0.0
            for i in range(26):
                observed = (letter_count[i] / total_letters) * 100.0
                expected = english_freq[i]
                freq_score -= abs(observed - expected) * 0.1
            score += freq_score
        
        # Space frequency (English text typically has 10-15% spaces)
        spaces = text.count(' ')
        if len(text) > 0:
            space_ratio = spaces / len(text)
            if 0.08 <= space_ratio <= 0.20:  # Reasonable space ratio
                score += 5.0
            else:
                score -= abs(space_ratio - 0.13) * 10.0
        
        return score
    
    def _isLikelyEnglish(self, text: str) -> bool:
        if not text:
            return False
        
        letters = sum(1 for c in text if c.isalpha())
        spaces = text.count(' ')
        
        return letters > len(text) * 0.6 and spaces > 0
    
    def _hexToBytes(self, hex_str: str) -> List[int]:
        bytes_data = []
        for i in range(0, len(hex_str), 2):
            if i + 1 < len(hex_str):
                try:
                    bytes_data.append(int(hex_str[i:i+2], 16))
                except ValueError:
                    continue
        return bytes_data
    
    def _tryKey(self, bytes_data: List[int], key: int) -> str:
        return ''.join(chr(byte_val ^ key) for byte_val in bytes_data)

Complexity

  • ⏰ Time complexity: O(n) where n is the length of the hex string, with enhanced scoring that includes frequency analysis but maintains linear time per key attempt.
  • 🧺 Space complexity: O(1) additional space for frequency analysis arrays and common word lists, plus O(n) for the input processing and result storage.