Given a string s consisting of lowercase English letters, check whether it can be rearranged such that no two adjacent characters are the same.
Examples:
Input: s = "aaabc"
Output: true
Explanation: "aaabc" can rearranged to "abaca" or "acaba" as no two adjacent characters are same in the output string.Input: s = "aaabb"
Output: true
Explanation: "aaabb" can rearranged to "ababa" as no two adjacent characters are same in the output string.Input: s = "aaaabc"
Output: false
Explanation: No combinations possible such that two adjacent characters are different.
Table of Content
[Naive Approach] Using Hash Map to Count Frequencies - O(n) Time and O(1) Space
The idea is to count how many times each character appears using a hash map, and look at the highest count among them. A valid rearrangement exists only if this maximum count is at most half the string's length, rounded up (the ceiling of n/2) - any more, and that character alone would need to occupy more than every alternate position, forcing two of its copies to end up next to each other no matter how the string is arranged.
Step by Step Implementation:
- Count the frequency of every character using a hash map.
- Find the maximum frequency among all characters.
- Check if this maximum frequency is at most ⌈n/2⌉ (computed as (n + 1) / 2 using integer division).
- Return true if the condition holds, false otherwise.
#include <iostream>
#include <string>
using namespace std;
bool canRearrange(string &s) {
int n = s.size();
// Voting phase: find a candidate using Boyer-Moore's algorithm
char candidate = '\0';
int count = 0;
for (char ch : s) {
if (count == 0) {
candidate = ch;
count = 1;
} else if (ch == candidate) {
count++;
} else {
count--;
}
}
// Verification phase: count the candidate's actual occurrences
count = 0;
for (char ch : s) {
if (ch == candidate) {
count++;
}
}
// Rearrangement is impossible only if some character's frequency
// exceeds ceil(n / 2)
return count <= (n + 1) / 2;
}
int main() {
string s = "aaabc";
cout << (canRearrange(s) ? "true" : "false") << endl;
return 0;
}
import java.util.HashMap;
class GFG {
static boolean canRearrange(String s) {
int n = s.length();
// Count the frequency of every character
HashMap<Character, Integer> freq = new HashMap<>();
for (char ch : s.toCharArray()) {
freq.put(ch, freq.getOrDefault(ch, 0) + 1);
}
// Find the maximum frequency among all characters
int maxFreq = 0;
for (int val : freq.values()) {
maxFreq = Math.max(maxFreq, val);
}
// Rearrangement is possible only if the maximum frequency
// does not exceed ceil(n / 2)
return maxFreq <= (n + 1) / 2;
}
public static void main(String[] args) {
String s = "aaabc";
System.out.println(canRearrange(s));
}
}
from collections import Counter
def canRearrange(s):
n = len(s)
# Count the frequency of every character
freq = Counter(s)
# Find the maximum frequency among all characters
maxFreq = max(freq.values())
# Rearrangement is possible only if the maximum frequency
# does not exceed ceil(n / 2)
return maxFreq <= (n + 1) // 2
s = "aaabc"
print("true" if canRearrange(s) else "false")
using System;
using System.Collections.Generic;
using System.Linq;
class GFG {
static bool canRearrange(string s) {
int n = s.Length;
// Count the frequency of every character
Dictionary<char, int> freq = new Dictionary<char, int>();
foreach (char ch in s) {
if (freq.ContainsKey(ch)) freq[ch]++;
else freq[ch] = 1;
}
// Find the maximum frequency among all characters
int maxFreq = freq.Values.Max();
// Rearrangement is possible only if the maximum frequency
// does not exceed ceil(n / 2)
return maxFreq <= (n + 1) / 2;
}
static void Main() {
string s = "aaabc";
Console.WriteLine(canRearrange(s) ? "true" : "false");
}
}
function canRearrange(s) {
const n = s.length;
// Count the frequency of every character
const freq = new Map();
for (const ch of s) {
freq.set(ch, (freq.get(ch) || 0) + 1);
}
// Find the maximum frequency among all characters
let maxFreq = 0;
for (const val of freq.values()) {
maxFreq = Math.max(maxFreq, val);
}
// Rearrangement is possible only if the maximum frequency
// does not exceed ceil(n / 2)
return maxFreq <= Math.floor((n + 1) / 2);
}
// Driver Code
const s = "aaabc";
console.log(canRearrange(s) ? "true" : "false");
Output
true
[Expected Approach] Using Boyer-Moore Voting Algorithm - O(n) Time and O(1) Space
The idea is to find a candidate for the most frequent character using Boyer-Moore's voting algorithm, then verify its actual count in a second pass. If that count exceeds ⌈n/2⌉, rearrangement is impossible; otherwise, it's always achievable.
Step by Step Implementation:
- Run Boyer-Moore's voting algorithm: maintain a candidate and a count, incrementing the count when the current character matches the candidate, decrementing otherwise, and switching candidates whenever the count drops to zero.
- After the voting phase, count how many times the resulting candidate actually appears in the string.
- Check if this count exceeds ⌈n/2⌉ (computed as (n + 1) / 2 using integer division).
- Return false if it does, true otherwise.
#include <iostream>
#include <string>
using namespace std;
bool canRearrange(string &s) {
int n = s.size();
// Voting phase: find a candidate using Boyer-Moore's algorithm
char candidate = '\0';
int count = 0;
for (char ch : s) {
if (count == 0) {
candidate = ch;
count = 1;
} else if (ch == candidate) {
count++;
} else {
count--;
}
}
// Verification phase: count the candidate's actual occurrences
count = 0;
for (char ch : s) {
if (ch == candidate) {
count++;
}
}
// Rearrangement is impossible only if some character's frequency
// exceeds ceil(n / 2)
return count <= (n + 1) / 2;
}
int main() {
string s = "aaabc";
cout << (canRearrange(s) ? "true" : "false") << endl;
return 0;
}
class GFG {
static boolean canRearrange(String s) {
int n = s.length();
// Voting phase: find a candidate using Boyer-Moore's algorithm
char candidate = '\0';
int count = 0;
for (char ch : s.toCharArray()) {
if (count == 0) {
candidate = ch;
count = 1;
} else if (ch == candidate) {
count++;
} else {
count--;
}
}
// Verification phase: count the candidate's actual occurrences
count = 0;
for (char ch : s.toCharArray()) {
if (ch == candidate) {
count++;
}
}
// Rearrangement is impossible only if some character's frequency
// exceeds ceil(n / 2)
return count <= (n + 1) / 2;
}
public static void main(String[] args) {
String s = "aaabc";
System.out.println(canRearrange(s));
}
}
def canRearrange(s):
n = len(s)
# Voting phase: find a candidate using Boyer-Moore's algorithm
candidate = None
count = 0
for ch in s:
if count == 0:
candidate = ch
count = 1
elif ch == candidate:
count += 1
else:
count -= 1
# Verification phase: count the candidate's actual occurrences
count = 0
for ch in s:
if ch == candidate:
count += 1
# Rearrangement is impossible only if some character's frequency
# exceeds ceil(n / 2)
return count <= (n + 1) // 2
s = "aaabc"
print("true" if canRearrange(s) else "false")
using System;
class GFG {
static bool canRearrange(string s) {
int n = s.Length;
// Voting phase: find a candidate using Boyer-Moore's algorithm
char candidate = '\0';
int count = 0;
foreach (char ch in s) {
if (count == 0) {
candidate = ch;
count = 1;
} else if (ch == candidate) {
count++;
} else {
count--;
}
}
// Verification phase: count the candidate's actual occurrences
count = 0;
foreach (char ch in s) {
if (ch == candidate) {
count++;
}
}
// Rearrangement is impossible only if some character's frequency
// exceeds ceil(n / 2)
return count <= (n + 1) / 2;
}
static void Main() {
string s = "aaabc";
Console.WriteLine(canRearrange(s) ? "true" : "false");
}
}
function canRearrange(s) {
const n = s.length;
// Voting phase: find a candidate using Boyer-Moore's algorithm
let candidate = null;
let count = 0;
for (const ch of s) {
if (count === 0) {
candidate = ch;
count = 1;
} else if (ch === candidate) {
count++;
} else {
count--;
}
}
// Verification phase: count the candidate's actual occurrences
count = 0;
for (const ch of s) {
if (ch === candidate) {
count++;
}
}
// Rearrangement is impossible only if some character's frequency
// exceeds ceil(n / 2)
return count <= Math.floor((n + 1) / 2);
}
// Driver Code
const s = "aaabc";
console.log(canRearrange(s) ? "true" : "false");
Output
true