The function below takes two BitSets, makes a copy of the first (it must not be overridden), intersects the copy with the second (bitwise AND) and returns the cardinality of the result.
public int getIntersectionSize(BitSet bits1, BitSet bits2) {
BitSet copy = (BitSet) bits1.clone();
copy.and(bits2);
return copy.cardinality();
}
I'm interested if this code can be sped up? This function is called billion of times so even a microsecond speed up makes sense plus I'm curious about the fastest possible code.
If you're going to use each BitSet several times, it could be worthwhile to create a long array corresponding to each BitSet. For each BitSet:
long[] longs = bitset.toLongArray();
Then you can use the following method, which avoids the overhead of creating a cloned BitSet. (This assumes that both arrays are the same length).
int getIntersectionSize(long[] bits1, long[] bits2) {
int nBits = 0;
for (int i=0; i<bits1.length; i++)
nBits += Long.bitCount(bits1[i] & bits2[i]);
return nBits;
}
Here is an alternative version, but I'm not sure if it is really faster, depends on nextSetBit.
public int getIntersectionsSize(BitSet bits1, BitSet bits2) {
int count = 0;
int i = bits1.nextSetBit(0);
int j = bits2.nextSetBit(0);
while (i >= 0 && j >= 0) {
if (i < j) {
i = bits1.nextSetBit(i + 1);
} else if (i > j) {
j = bits2.nextSetBit(j + 1);
} else {
count++;
i = bits1.nextSetBit(i + 1);
j = bits2.nextSetBit(j + 1);
}
}
return count;
}
The above is the readable version, hopefully good enough for the compiler, but you could optimize it manually I guess:
public int getIntersectionsSize(BitSet bits1, BitSet bits2) {
int count = 0;
for (int i = bits1.nextSetBit(0), j = bits2.nextSetBit(0); i >= 0 && j >= 0; ) {
while (i < j) {
i = bits1.nextSetBit(i + 1);
if (i < 0)
return count;
}
if (i == j) {
count++;
i = bits1.nextSetBit(i + 1);
}
while (j < i) {
j = bits2.nextSetBit(j + 1);
if (j < 0)
return count;
}
if (i == j) {
count++;
j = bits2.nextSetBit(j + 1);
}
}
return count;
}
I've been looking for a solution to this recently and here's what I came up with:
int intersectionCardinality(final BitSet lhs, final BitSet rhs) {
int lhsNext;
int retVal = 0;
int rhsNext = 0;
while ((lhsNext = lhs.nextSetBit(rhsNext)) != -1 &&
(rhsNext = rhs.nextSetBit(lhsNext)) != -1) {
if (rhsNext == lhsNext) {
retVal++;
rhsNext++;
}
}
return retVal;
}
Perhaps someone would like to take the time to compare the different solutions here and post the results...
Related
Trying to solve this problem with recursion and memoization but for input 7168 I'm getting wrong answer.
public int numSquares(int n) {
Map<Integer, Integer> memo = new HashMap();
List<Integer> list = fillSquares(n, memo);
if (list == null)
return 1;
return helper(list.size()-1, list, n, memo);
}
private int helper(int index, List<Integer> list, int left, Map<Integer, Integer> memo) {
if (left == 0)
return 0;
if (left < 0 || index < 0)
return Integer.MAX_VALUE-1;
if (memo.containsKey(left)) {
return memo.get(left);
}
int d1 = 1+helper(index, list, left-list.get(index), memo);
int d2 = 1+helper(index-1, list, left-list.get(index), memo);
int d3 = helper(index-1, list, left, memo);
int d = Math.min(Math.min(d1,d2), d3);
memo.put(left, d);
return d;
}
private List<Integer> fillSquares(int n, Map<Integer, Integer> memo) {
int curr = 1;
List<Integer> list = new ArrayList();
int d = (int)Math.pow(curr, 2);
while (d < n) {
list.add(d);
memo.put(d, 1);
curr++;
d = (int)Math.pow(curr, 2);
}
if (d == n)
return null;
return list;
}
I'm calling like this:
numSquares(7168)
All test cases pass (even complex cases), but this one fails. I suspect something is wrong with my memoization but cannot pinpoint what exactly. Any help will be appreciated.
You have the memoization keyed by the value to be attained, but this does not take into account the value of index, which actually puts restrictions on which powers you can use to attain that value. That means that if (in the extreme case) index is 0, you can only reduce what is left with one square (1²), which rarely is the optimal way to form that number. So in a first instance memo.set() will register a non-optimal number of squares, which later will get updated by other recursive calls which are pending in the recursion tree.
If you add some conditional debugging code, you'll see that map.set is called for the same value of left multiple times, and with differing values. This is not good, because that means the if (memo.has(left)) block will execute for cases where that value is not guaranteed to be optimal (yet).
You could solve this by incorporating the index in your memoization key. This increases the space used for memoization, but it will work. I assume you can work this out.
But according to Lagrange's four square theorem every natural number can be written as the sum of at most four squares, so the returned value should never be 5 or more. You can shortcut the recursion when you get passed that number of terms. This reduces the benefit of using memoization.
Finally, there is a mistake in fillSquares: it should add n itself also when it is a perfect square, otherwise you'll not find solutions that should return 1.
Not sure about your bug, here is a short dynamic programming Solution:
Java
public class Solution {
public static final int numSquares(
final int n
) {
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for (int i = 1; i <= n; i++) {
int j = 1;
int min = Integer.MAX_VALUE;
while (i - j * j >= 0) {
min = Math.min(min, dp[i - j * j] + 1);
++j;
}
dp[i] = min;
}
return dp[n];
}
}
C++
// Most of headers are already included;
// Can be removed;
#include <iostream>
#include <cstdint>
#include <vector>
#include <algorithm>
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
#define MAX INT_MAX
using ValueType = std::uint_fast32_t;
struct Solution {
static const int numSquares(
const int n
) {
if (n < 1) {
return 0;
}
static std::vector<ValueType> count_perfect_squares{0};
while (std::size(count_perfect_squares) <= n) {
const ValueType len = std::size(count_perfect_squares);
ValueType count_squares = MAX;
for (ValueType index = 1; index * index <= len; ++index) {
count_squares = std::min(count_squares, 1 + count_perfect_squares[len - index * index]);
}
count_perfect_squares.emplace_back(count_squares);
}
return count_perfect_squares[n];
}
};
int main() {
std::cout << std::to_string(Solution().numSquares(12) == 3) << "\n";
return 0;
}
Python
Here we can simply use lru_cache:
class Solution:
dp = [0]
#functools.lru_cache
def numSquares(self, n):
dp = self.dp
while len(dp) <= n:
dp += min(dp[-i * i] for i in range(1, int(len(dp) ** 0.5 + 1))) + 1,
return dp[n]
Here are LeetCode's official solutions with comments:
Java: DP
class Solution {
public int numSquares(int n) {
int dp[] = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
// bottom case
dp[0] = 0;
// pre-calculate the square numbers.
int max_square_index = (int) Math.sqrt(n) + 1;
int square_nums[] = new int[max_square_index];
for (int i = 1; i < max_square_index; ++i) {
square_nums[i] = i * i;
}
for (int i = 1; i <= n; ++i) {
for (int s = 1; s < max_square_index; ++s) {
if (i < square_nums[s])
break;
dp[i] = Math.min(dp[i], dp[i - square_nums[s]] + 1);
}
}
return dp[n];
}
}
Java: Greedy
class Solution {
Set<Integer> square_nums = new HashSet<Integer>();
protected boolean is_divided_by(int n, int count) {
if (count == 1) {
return square_nums.contains(n);
}
for (Integer square : square_nums) {
if (is_divided_by(n - square, count - 1)) {
return true;
}
}
return false;
}
public int numSquares(int n) {
this.square_nums.clear();
for (int i = 1; i * i <= n; ++i) {
this.square_nums.add(i * i);
}
int count = 1;
for (; count <= n; ++count) {
if (is_divided_by(n, count))
return count;
}
return count;
}
}
Java: Breadth First Search
class Solution {
public int numSquares(int n) {
ArrayList<Integer> square_nums = new ArrayList<Integer>();
for (int i = 1; i * i <= n; ++i) {
square_nums.add(i * i);
}
Set<Integer> queue = new HashSet<Integer>();
queue.add(n);
int level = 0;
while (queue.size() > 0) {
level += 1;
Set<Integer> next_queue = new HashSet<Integer>();
for (Integer remainder : queue) {
for (Integer square : square_nums) {
if (remainder.equals(square)) {
return level;
} else if (remainder < square) {
break;
} else {
next_queue.add(remainder - square);
}
}
}
queue = next_queue;
}
return level;
}
}
Java: Most efficient solution using math
Runtime: O(N ^ 0.5)
Memory: O(1)
class Solution {
protected boolean isSquare(int n) {
int sq = (int) Math.sqrt(n);
return n == sq * sq;
}
public int numSquares(int n) {
// four-square and three-square theorems.
while (n % 4 == 0)
n /= 4;
if (n % 8 == 7)
return 4;
if (this.isSquare(n))
return 1;
// enumeration to check if the number can be decomposed into sum of two squares.
for (int i = 1; i * i <= n; ++i) {
if (this.isSquare(n - i * i))
return 2;
}
// bottom case of three-square theorem.
return 3;
}
}
You have been given a binary string containing only the characters '1' and '0'.
Calculate how many characters of the string need to be changed in order to make the binary string such that each of its substrings of at least a certain length contains at least one "1" character.
I came to think of the following idea but it fails for many testcases:
public static int minimumMoves(String s, int d) {
int n = s.length();
int i=0, answer = 0;
while(i<n)
{
boolean hasOne = false;
int j=i;
while(j<n && j<i+d)
{
if(s.charAt(j) == '1')
{
hasOne = true;
break;
}
j++;
}
if(!hasOne) {
answer++;
i += d;
}
else i++;
}
return answer;
}
Also my algorithm runs on O(|s|2) time. Can anyone suggest ideas on O(|s|) time?
Just throwing off an idea:
return s.split("(?<=\\G.{" + String.valueof(d) + "})").stream().filter(str -> str.contains("1")).count()
You just need to break ensure there is no run of d zeros.
public static int minimumMoves(String s, int d) {
int result = 0;
int runLength = 0;
for(char c: s.toCharArray()) {
if (c == '0') {
runLength += 1;
if (runLength == d) { // we need to break this run
result += 1;
runLength = 0;
}
} else {
runLength = 0;
}
}
return result;
}
I used the sliding window technique and Deque to solve this. This is my accepted solution:
public static int minimumMoves(String s, int d) {
int n = s.length();
Deque<Character> dq = new LinkedList<>();
int count = 0, answer = 0;
for(int i=0; i<d; i++)
{
if(s.charAt(i) == '1') count++;
dq.addLast(s.charAt(i));
}
if(count == 0) {
answer++;
count++;
dq.removeLast();
dq.addLast('1');
}
int i=d;
while(i<n)
{
if(dq.getFirst() == '1') count--;
dq.removeFirst();
if(s.charAt(i) == '1') count++;
dq.addLast(s.charAt(i));
if(count == 0)
{
answer++;
dq.removeLast();
dq.addLast('1');
count++;
}
i++;
}
return answer;
}
You just need to use a sliding window and a count of 1s so far at each index. Use a sliding window of d and if you don't see any ones so far, update the last index of that window with 1 and increment the result.
Code below:
public static int minimumMoves(String s, int d) {
int n = s.length();
int[] count = new int[n+1];
int res = 0;
for ( int i = 1; i <= d; i++ ) {
if ( s.charAt(i-1) == '1') count[i] = count[i-1]+1;
else count[i] = count[i-1];
}
if ( count[d] == 0 ) {
res++;
count[d] = 1;
}
for ( int i = d+1; i <= n; i++ ) {
if ( s.charAt(i-1) == '0' ) {
count[i] = count[i-1];
int ones = count[i] - count[i-d];
if ( ones == 0 ) {
count[i] = count[i-1] + 1;
res++;
}
} else {
count[i] = count[i-1] + 1;
}
}
return res;
}
Thought of another implementation you can do for this by working from the maximum possible changes (assumes at start that all values are '0' in String), reduce it when it finds a '1' value, and then jump to the next substring start. This allows it to run in O(n) and Ω(n/m) (n = String length, m = Substring length).
public static int minimumMoves(String s, int d)
{
char[] a = s.toCharArray();
//Total possible changes (not counting tail)
if(a.length < d)
return 0;
int t = (int) a.length / d;
//Total possible changes (counting tail)
//int t = (int) Math.ceil((double) a.length / (double) d);
for(int i = 0; i < a.length; i++)
{
if(a[i] == '1')
{
t--;
//Calculate index for start of next substring
i = (i / d + 1) * d - 1;
}
}
return t;
}
I'm trying to calculate the time complexity of this code that sums the odd numbers of an array. I have done two methods and now I need to calculate the order complexity O(n)
This one is done by weak post-condition.
private static int sumaImparDebilit(int t[], int desde, int hasta) {
if (desde==hasta) {
if ((t[desde] % 2) == 1) {
return t[desde];
}
return 0;
}
if (t[desde]%2 == 1) {
return (t[desde] + sumaImparDebilit(t,(desde+1),hasta));
}
return (sumaImparDebilit(t,(desde+1),hasta));
}
This one is done by strong pre-condition.
private static int sumaImparFortalec(int t[], int hasta, int limite, int parcial) {
if (hasta <= limite) {
if ((t[hasta] % 2) == 1) {
return sumaImparFortalec(t,(hasta + 1),limite,(parcial + t[hasta]));
} else {
return sumaImparFortalec(t,(hasta + 1),limite,(parcial));
}
}
else {
return parcial;
}
}
I don’t know what you mean by “weak” and “strong” conditions, but both have time complexity O(n) and employ (for no good reason) recursion.
Surely this is simplest, and fastest:
int sum = 0;
for (int i = 0; i < t.length; i++)
if (t[i] % 2 == 1)
sum += t[i];
I'm trying to solve an "Almost Sorted" challenge in hackerrank the problem is:
Given an array with elements, can you sort this array in ascending order using only one of the following operations?
Swap two elements.
Reverse one sub-segment.
Input Format
The first line contains a single integer, , which indicates the size of the array.
The next line contains integers separated by spaces.
Sample Input #1
2
4 2
Sample Output #1
yes
swap 1 2
Sample Input #2
3
3 1 2
Sample Output #2
no
Sample Input #3
6
1 5 4 3 2 6
Sample Output #3
yes
reverse 2 5
I tried to solve the challenge and my code is working but it seems it's to slow for big arrays.
Kindly asking you to help me to find a better solution for mentioned problem.
Below is my code:
import java.util.*;
public class Solution
{
private static int[] arr;
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
int N = in.nextInt();
arr = new int[N];
for (int i = 0; i < N; i++)
{
arr[i] = in.nextInt();
}
if (IsSorted(arr))
{
System.out.println("yes");
return;
}
if(CheckSingleSwap(arr))
return;
if(CheckSingleReverse(arr))
return;
System.out.println("no");
}
private static boolean CheckSingleReverse(int[] arr)
{
int length = arr.length;
int limit = length - 2;
int current = 1;
List<Integer> indexes = new ArrayList<Integer>();
while (current < limit)
{
for (int i = 0; i < length; i++)
{
int temp = current + i;
for (int j = i; j <= temp && temp < length; j++)
{
indexes.add(j);
}
if (IsSorted(ReverseArrayPart(arr, indexes)))
{
System.out.println("yes");
System.out.println("reverse " + (indexes.get(0) + 1) + " " + (indexes.get(indexes.size() - 1) + 1));
return true;
}
indexes.clear();
}
current++;
}
return false;
}
private static int[] ReverseArrayPart(int[] arr, List<Integer> indexes)
{
int[] result = new int[arr.length];
int[] arrayPart = new int[indexes.size()];
int j = 0;
for (int i = 0; i < arr.length; i++)
{
if (indexes.contains(i))
{
arrayPart[j] = arr[i];
j++;
}
result[i] = arr[i];
}
for(int i = 0; i < arrayPart.length / 2; i++)
{
int temp = arrayPart[i];
arrayPart[i] = arrayPart[arrayPart.length - i - 1];
arrayPart[arrayPart.length - i - 1] = temp;
}
j = 0;
for (int i = 0; i < result.length; i++)
{
if (indexes.contains(i))
{
result[i] = arrayPart[j];
j++;
}
}
return result;
}
private static boolean CheckSingleSwap(int[] arr)
{
int count = 0;
int[] B = Arrays.copyOf(arr, arr.length);
Arrays.sort(B);
List<Integer> indexes = new ArrayList<Integer>();
for(int i = 0; i < arr.length; i++)
{
if(arr[i] != B[i])
{
count++;
indexes.add(i+1);
}
}
if(count > 2)
return false;
System.out.println("yes");
System.out.println("swap " + indexes.get(0) + " " + indexes.get(1));
return true;
}
private static boolean IsSorted(int[] arr)
{
int length = arr.length;
for (int i = 0; i < length - 1; i++)
{
if (arr[i] > arr[i + 1])
{
return false;
}
}
return true;
}
}
For the following code, pass in A as the original array and B as the sorted array.
CheckSingleSwap:
Instead of adding the indices to another list, store the first swap you encounter, and keep going; if you find the corresponding other swap, then store it and record the finding; if you find a different swap, exit with false. At the end if you've recorded the finding, print the corresponding indices.
private static boolean CheckSingleSwap(int[] A, int[] B)
{
int L = A.length;
int firstSwap = -1, secondSwap = -1;
for(int i = 0; i < L; i++)
{
if(A[i] != B[i])
{
if (firstSwap == -1)
firstSwap = i;
else if (secondSwap == -1 && A[i] == B[firstSwap] && A[firstSwap] == B[i])
secondSwap = i;
else
return false;
}
}
if (firstSwap != -1 && secondSwap != -1)
{
System.out.println("yes");
System.out.println("swap " + (firstSwap + 1) + " " + (secondSwap + 1));
return true;
}
System.out.println("array is already sorted!");
return false; // or whatever you decide to do; maybe even an exception or enumerated type
}
CheckSingleReverse:
You are doing WAY too much here! You seem to be brute forcing every single possible case (at first glance).
What you can do instead is to find the region where all the numbers are different. If there are more than two of these, or two which are separated by more than one element, then return false immediately.
The reason for the "more than one" thing above is because of odd-number length regions - the middle element would be the same. If you find such two regions, treat them as one. Then you can proceed to find out if the region is reversed.
private static boolean CheckSingleReverse(int[] A, int[] B)
{
// find region
int L = A.length;
int diffStart = -1, diffEnd = -1; boolean mid = false, found = false;
for (int i = 0; i < L; i++)
{
if (A[i] != B[i])
{
if (found)
{
if (i - diffEnd == 2 && !mid)
{
mid = true;
found = false;
diffEnd = -1;
}
else
return false;
}
else if (diffStart == -1)
diffStart = i;
}
else
if (diffStart != -1 && diffEnd == -1)
{
found = true;
diffEnd = i - 1;
}
}
if (diffEnd == -1)
{
if (A[L - 1] != B[L - 1])
diffEnd = L - 1;
else if (!found)
{
System.out.println("array is already sorted!");
return false;
}
}
// find out if it's reversed
int count = (diffEnd - diffStart + 1) / 2;
for (int i = 0; i < count; i++)
{
int oneEnd = diffStart + i, otherEnd = diffEnd - i;
if (!(A[oneEnd] == B[otherEnd] && A[otherEnd] == B[oneEnd]))
return false;
}
System.out.println("yes");
System.out.println("reverse " + (diffStart + 1) + " " + (diffEnd + 1));
return true;
}
Just to give you an idea of the performance boost, on ideone.com, with an array length of 150, the original implementation of CheckSingleReverse took 1.83 seconds, whereas the new one took just 0.1 seconds. With a length of 250, the original actually exceeded the computational time limit (5 seconds), whereas the new one still took just 0.12 seconds.
From this it would seem that your implementation takes exponential time, whereas mine is linear time (ignoring the sorting).
Funnily enough, with an array size of 3 million I'm still getting around 0.26 seconds (ideone's execution time fluctuates a bit as well, probs due to demand)
I have a function it returns prime factors of a number but when I initialize int array I set size.So the result consists unnecessary zeros.How can I return result array without zeros or how can I initialize array applicable size? I am not using Lists
public static int[] encodeNumber(int n){
int i;
int j = 0;
int[] prime_factors = new int[j];
if(n <= 1) return null;
for(i = 2; i <= n; i++){
if(n % i == 0){
n /= i;
prime_factors[j] = i;
i--;
j++;
}
}
return prime_factors;
}
Thanx!!!
Here is a quick way to get about the prime factors problem that I recently worked out. I don't claim it is original, but I did create it on my own. Actually had to do this in C, where I wanted to malloc only once.
public static int[] getPrimeFactors(final int i) {
return getPrimeFactors1(i, 0, 2);
}
private static int[] getPrimeFactors1(int number, final int numberOfFactorsFound, final int startAt) {
if (number <= 1) { return new int[numberOfFactorsFound]; }
if (isPrime(number)) {
final int[] toReturn = new int[numberOfFactorsFound + 1];
toReturn[numberOfFactorsFound] = number;
return toReturn;
}
final int[] toReturn;
int currentFactor = startAt;
final int currentIndex = numberOfFactorsFound;
int numberOfRepeatations = 0;
// we can loop unbounded by the currentFactor, because
// All non prime numbers can be represented as product of primes!
while (!(isPrime(currentFactor) && number % currentFactor == 0)) {
currentFactor += currentFactor == 2 ? 1 : 2;
}
while (number % currentFactor == 0) {
number /= currentFactor;
numberOfRepeatations++;
}
toReturn = getPrimeFactors1(number, currentIndex + numberOfRepeatations, currentFactor + (currentFactor == 2 ? 1 : 2));
while (numberOfRepeatations > 0) {
toReturn[currentIndex + --numberOfRepeatations] = currentFactor;
}
return toReturn;
}
Allocate as many factors as you think the number may have (32 sounds like a good candidate), and then use Arrays.copyOf() to cut off the array at the actual limit:
return Arrays.copyOf(prime_factors, j);