3576. Transform Array to All Equal Elements
Problem Description
You are given an integer array nums
of size n
containing only 1
and -1
, and an integer k
.
You can perform the following operation at most k
times:
- Choose an index
i
(0 <= i < n - 1
), and multiply bothnums[i]
andnums[i + 1]
by-1
.
Note that you can choose the same index i
more than once in different operations.
Return true
if it is possible to make all elements of the array equal after at most k
operations, and false
otherwise.
Intuition
Because every operation flips two adjacent elements, the pattern of changes we make spreads through the array. To make all elements equal, all elements must end up as either 1
or -1
. Since each operation flips a pair, we can think in terms of transforming the array step-by-step to one of these uniform arrays.
If we start from the left, whenever an element does not match our target value, we can perform an operation at that position to flip it (and its neighbor). This way, each operation "fixes" mismatches as we go. We just need to count how many operations are required to achieve all equal elements and check if the total is within the allowed number k
. We consider both possible targets (nums[0]
and -nums[0]
) to see if either is reachable within k
moves. This greedy process guarantees that if the goal is possible, we'll find a way by always "fixing" elements as soon as they don't match our target.
Solution Approach
The main idea is to check whether we can convert the entire array into either all 1
s or all -1
s in at most k
moves. To do this, we define a function check(target, k)
that simulates transforming the array so that every value matches target
.
Here's how the process works:
- Initialize a counter
cnt
to track how many operations we've made, and a variablesign
to simulate the current state of flipping (starting with1
). - Loop through the array from left to right, except the last element:
- For each
i
, calculate the current value asnums[i] * sign
. This reflects the effect of all previous flips. - If this value is already equal to the
target
, do nothing for this element and setsign
to1
. - Otherwise, we need to flip at this position. Increment
cnt
and setsign
to-1
, which flips the state for subsequent elements.
- For each
- After the loop, check if the number of required operations does not exceed
k
and the final element (after considering all flips) matches thetarget
.
Finally, check both possibilities: making all elements equal to nums[0]
, or to -nums[0]
.
In summary:
- This approach uses a single pass (
O(n)
) and requires only counters and basic variables (no complex data structures). - The greedy pattern of fixing mismatches from left to right ensures minimum operations.
Pseudocode for reference:
def check(target, k): cnt = 0 sign = 1 for i from 0 to n-2: x = nums[i] * sign if x == target: sign = 1 else: sign = -1 cnt += 1 return cnt <= k and nums[-1] * sign == target return check(nums[0], k) or check(-nums[0], k)
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Consider nums = [1, -1, 1, -1]
and k = 2
.
We want to see if we can make all elements the same (either all 1
s or all -1
s) in at most 2 operations, where each operation flips two adjacent values.
First, try making all elements 1
(target = 1
):
Initial array: [1, -1, 1, -1]
Let cnt = 0
(operation count), sign = 1
(current flip state)
- At index 0:
nums[0] * sign = 1 * 1 = 1
(matches target 1), do nothing,sign
stays 1. - At index 1:
nums[1] * sign = -1 * 1 = -1
(doesn't match target), flip at index 1:- Increment
cnt
to 1. - Set
sign = -1
(flip for future elements).
- Increment
- At index 2:
nums[2] * sign = 1 * -1 = -1
(doesn't match target), flip at index 2:- Increment
cnt
to 2. - Set
sign = -1
(flip for future elements).
- Increment
After loop:
nums[3] * sign = -1 * -1 = 1
(matches target)
Total operations: 2, which is within k
.
So, it's possible to make all elements 1
with 2 flips.
For completeness, try making all elements -1
(target = -1
):
Reset cnt = 0
, sign = 1
.
- At index 0:
nums[0] * sign = 1 * 1 = 1
(doesn't match-1
), flip at index 0:cnt = 1
,sign = -1
- At index 1:
nums[1] * sign = -1 * -1 = 1
(doesn't match-1
), flip at index 1:cnt = 2
,sign = -1
- At index 2:
nums[2] * sign = 1 * -1 = -1
(matches target),sign = 1
After loop:
nums[3] * sign = -1 * 1 = -1
(matches target)
Total operations: 2, still within k
.
Conclusion
Both transformations are possible with 2 operations.
Result: true
Solution Implementation
1from typing import List
2
3class Solution:
4 def canMakeEqual(self, nums: List[int], k: int) -> bool:
5 # Helper function to check if it is possible to make all elements equal to 'target'
6 def check(target: int, k: int) -> bool:
7 count, sign = 0, 1
8 n = len(nums)
9 for i in range(n - 1):
10 current = nums[i] * sign
11 if current == target:
12 sign = 1 # Keep sign if number matches the target
13 else:
14 sign = -1 # Flip sign if it does not match
15 count += 1 # Increment number of changes
16 # Return True if total changes do not exceed k and last number matches target
17 return count <= k and nums[-1] * sign == target
18
19 # Try making all numbers equal to nums[0] or -nums[0]
20 return check(nums[0], k) or check(-nums[0], k)
21
1class Solution {
2 // Main function to determine if it's possible to make all elements equal with at most k changes
3 public boolean canMakeEqual(int[] nums, int k) {
4 // Check for two possible targets: nums[0] and -nums[0]
5 return check(nums, nums[0], k) || check(nums, -nums[0], k);
6 }
7
8 // Helper function to check if all elements can be equal to target with at most k flips
9 private boolean check(int[] nums, int target, int k) {
10 int flipCount = 0; // Number of flips performed
11 int currSign = 1; // Current sign multiplication for each number
12
13 // Iterate through the array except the last element
14 for (int i = 0; i < nums.length - 1; ++i) {
15 int value = nums[i] * currSign;
16 if (value == target) {
17 // No flip required, keep the current sign
18 currSign = 1;
19 } else {
20 // Flip required: change sign and increment flip count
21 currSign = -1;
22 ++flipCount;
23 }
24 }
25
26 // Check total flips and if the last element matches the target
27 return flipCount <= k && nums[nums.length - 1] * currSign == target;
28 }
29}
30
1class Solution {
2public:
3 // Determines if it is possible to make all numbers in nums equal to either nums[0] or -nums[0] using at most k operations
4 bool canMakeEqual(vector<int>& nums, int k) {
5 // Lambda to check if all can be made equal to `target` in at most `k` changes
6 auto check = [&](int target, int maxOperations) -> bool {
7 int n = nums.size();
8 int operationCount = 0; // Number of necessary operations
9 int sign = 1; // Current sign applied to numbers
10
11 // Iterate through all elements except the last
12 for (int i = 0; i < n - 1; ++i) {
13 int val = nums[i] * sign;
14
15 // If current value equals target, keep current sign
16 if (val == target) {
17 sign = 1;
18 } else {
19 // Otherwise, flip sign and increment operation count
20 sign = -1;
21 ++operationCount;
22 }
23 }
24
25 // Check if operations used are within limit and last value matches target (considering the sign)
26 return operationCount <= maxOperations && nums[n - 1] * sign == target;
27 };
28
29 // Check if we can make all numbers equal to nums[0] or -nums[0]
30 return check(nums[0], k) || check(-nums[0], k);
31 }
32};
33
1/**
2 * Determines if it is possible to make all elements equal by at most k sign flips.
3 * @param nums - Array of integers.
4 * @param k - Maximum allowed sign flips.
5 * @returns True if possible, otherwise false.
6 */
7function canMakeEqual(nums: number[], k: number): boolean {
8 /**
9 * Checks if all elements in nums can be made equal to a target by at most k sign flips.
10 * @param target - The target value to match.
11 * @param k - Maximum allowed sign flips.
12 * @returns True if possible, otherwise false.
13 */
14 function check(target: number, k: number): boolean {
15 let flipCount = 0; // Number of sign flips used
16 let currentSign = 1; // Current sign (1 or -1) applied to elements
17
18 // Iterate through all elements except the last
19 for (let i = 0; i < nums.length - 1; i++) {
20 const valueWithSign = nums[i] * currentSign;
21 if (valueWithSign === target) {
22 // No sign flip needed, continue
23 currentSign = 1;
24 } else {
25 // Perform a sign flip
26 currentSign = -1;
27 flipCount++;
28 }
29 }
30 // Check if flip count is within allowed k, and the last element matches the target
31 return flipCount <= k && nums[nums.length - 1] * currentSign === target;
32 }
33
34 // Try making all numbers equal to nums[0] or -nums[0]
35 return check(nums[0], k) || check(-nums[0], k);
36}
37
Time and Space Complexity
The time complexity of the code is O(n)
, where n
is the length of the input array nums
. This is because the function check
iterates through the array once for each of its two calls.
The space complexity is O(1)
since only a constant amount of extra space is used for variables regardless of the input size.
The three-steps of Depth First Search are:
- Identify states;
- Draw the state-space tree;
- DFS on the state-space tree.
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donโt Miss This!