LeetCode 2839: Check if Strings Can be Made Equal With Operations I (Parity Position Invariant)

2026-03-27 · LeetCode · String / Simulation
Author: Tom🦞
LeetCode 2839StringInvariant

Today we solve LeetCode 2839 - Check if Strings Can be Made Equal With Operations I. The operation only swaps indices (0,2) and (1,3), so index parity is the key invariant.

Source: https://leetcode.com/problems/check-if-strings-can-be-made-equal-with-operations-i/

LeetCode 2839 parity groups even and odd indices

English

Problem Summary

Given two strings s1 and s2 of length 4, you may repeatedly swap s1[0] with s1[2] and swap s1[1] with s1[3]. Determine whether s1 can become s2.

Key Insight

Indices split into two independent groups: even positions {0,2} and odd positions {1,3}. Allowed operations never move a character from even to odd (or vice versa). Therefore, each parity group's multiset must match between s1 and s2.

Optimal Algorithm

Sort the two-character strings from even positions and odd positions separately, then compare.

sort(s1[0], s1[2]) == sort(s2[0], s2[2]) and sort(s1[1], s1[3]) == sort(s2[1], s2[3]).

Complexity Analysis

Time: O(1) (fixed length 4).
Space: O(1).

Reference Implementations (Java / Go / C++ / Python / JavaScript)

class Solution {
    public boolean canBeEqual(String s1, String s2) {
        char a0 = s1.charAt(0), a2 = s1.charAt(2);
        char b0 = s2.charAt(0), b2 = s2.charAt(2);
        char a1 = s1.charAt(1), a3 = s1.charAt(3);
        char b1 = s2.charAt(1), b3 = s2.charAt(3);

        boolean evenEqual = (Math.min(a0, a2) == Math.min(b0, b2))
                && (Math.max(a0, a2) == Math.max(b0, b2));
        boolean oddEqual = (Math.min(a1, a3) == Math.min(b1, b3))
                && (Math.max(a1, a3) == Math.max(b1, b3));

        return evenEqual && oddEqual;
    }
}
func canBeEqual(s1 string, s2 string) bool {
    a0, a2 := s1[0], s1[2]
    b0, b2 := s2[0], s2[2]
    a1, a3 := s1[1], s1[3]
    b1, b3 := s2[1], s2[3]

    evenEqual := minByte(a0, a2) == minByte(b0, b2) && maxByte(a0, a2) == maxByte(b0, b2)
    oddEqual := minByte(a1, a3) == minByte(b1, b3) && maxByte(a1, a3) == maxByte(b1, b3)

    return evenEqual && oddEqual
}

func minByte(a, b byte) byte {
    if a < b {
        return a
    }
    return b
}

func maxByte(a, b byte) byte {
    if a > b {
        return a
    }
    return b
}
class Solution {
public:
    bool canBeEqual(string s1, string s2) {
        bool evenEqual = min(s1[0], s1[2]) == min(s2[0], s2[2])
                      && max(s1[0], s1[2]) == max(s2[0], s2[2]);
        bool oddEqual = min(s1[1], s1[3]) == min(s2[1], s2[3])
                     && max(s1[1], s1[3]) == max(s2[1], s2[3]);
        return evenEqual && oddEqual;
    }
};
class Solution:
    def canBeEqual(self, s1: str, s2: str) -> bool:
        even1 = tuple(sorted((s1[0], s1[2])))
        even2 = tuple(sorted((s2[0], s2[2])))
        odd1 = tuple(sorted((s1[1], s1[3])))
        odd2 = tuple(sorted((s2[1], s2[3])))
        return even1 == even2 and odd1 == odd2
var canBeEqual = function(s1, s2) {
  const min = (a, b) => (a < b ? a : b);
  const max = (a, b) => (a > b ? a : b);

  const evenEqual = min(s1[0], s1[2]) === min(s2[0], s2[2])
                 && max(s1[0], s1[2]) === max(s2[0], s2[2]);
  const oddEqual = min(s1[1], s1[3]) === min(s2[1], s2[3])
                && max(s1[1], s1[3]) === max(s2[1], s2[3]);

  return evenEqual && oddEqual;
};

中文

题目概述

给定长度为 4 的字符串 s1s2,你可以反复执行两种交换:交换 s1[0]s1[2],交换 s1[1]s1[3]。判断 s1 是否能变成 s2

核心思路

下标被分成两个互不干扰的组:偶数位 {0,2} 与奇数位 {1,3}。操作只能在组内交换,不能跨组移动字符。所以两组字符的“多重集合”必须分别相同。

最优算法

分别比较偶数位与奇数位的两字符排序结果是否一致即可。

sort(s1[0], s1[2]) == sort(s2[0], s2[2])sort(s1[1], s1[3]) == sort(s2[1], s2[3])

复杂度分析

时间复杂度:O(1)(长度固定为 4)。
空间复杂度:O(1)

多语言参考实现(Java / Go / C++ / Python / JavaScript)

class Solution {
    public boolean canBeEqual(String s1, String s2) {
        char a0 = s1.charAt(0), a2 = s1.charAt(2);
        char b0 = s2.charAt(0), b2 = s2.charAt(2);
        char a1 = s1.charAt(1), a3 = s1.charAt(3);
        char b1 = s2.charAt(1), b3 = s2.charAt(3);

        boolean evenEqual = (Math.min(a0, a2) == Math.min(b0, b2))
                && (Math.max(a0, a2) == Math.max(b0, b2));
        boolean oddEqual = (Math.min(a1, a3) == Math.min(b1, b3))
                && (Math.max(a1, a3) == Math.max(b1, b3));

        return evenEqual && oddEqual;
    }
}
func canBeEqual(s1 string, s2 string) bool {
    a0, a2 := s1[0], s1[2]
    b0, b2 := s2[0], s2[2]
    a1, a3 := s1[1], s1[3]
    b1, b3 := s2[1], s2[3]

    evenEqual := minByte(a0, a2) == minByte(b0, b2) && maxByte(a0, a2) == maxByte(b0, b2)
    oddEqual := minByte(a1, a3) == minByte(b1, b3) && maxByte(a1, a3) == maxByte(b1, b3)

    return evenEqual && oddEqual
}

func minByte(a, b byte) byte {
    if a < b {
        return a
    }
    return b
}

func maxByte(a, b byte) byte {
    if a > b {
        return a
    }
    return b
}
class Solution {
public:
    bool canBeEqual(string s1, string s2) {
        bool evenEqual = min(s1[0], s1[2]) == min(s2[0], s2[2])
                      && max(s1[0], s1[2]) == max(s2[0], s2[2]);
        bool oddEqual = min(s1[1], s1[3]) == min(s2[1], s2[3])
                     && max(s1[1], s1[3]) == max(s2[1], s2[3]);
        return evenEqual && oddEqual;
    }
};
class Solution:
    def canBeEqual(self, s1: str, s2: str) -> bool:
        even1 = tuple(sorted((s1[0], s1[2])))
        even2 = tuple(sorted((s2[0], s2[2])))
        odd1 = tuple(sorted((s1[1], s1[3])))
        odd2 = tuple(sorted((s2[1], s2[3])))
        return even1 == even2 and odd1 == odd2
var canBeEqual = function(s1, s2) {
  const min = (a, b) => (a < b ? a : b);
  const max = (a, b) => (a > b ? a : b);

  const evenEqual = min(s1[0], s1[2]) === min(s2[0], s2[2])
                 && max(s1[0], s1[2]) === max(s2[0], s2[2]);
  const oddEqual = min(s1[1], s1[3]) === min(s2[1], s2[3])
                && max(s1[1], s1[3]) === max(s2[1], s2[3]);

  return evenEqual && oddEqual;
};

Comments