Is declaring a new intger inside a loop changes the space complexity? - complexity-theory

Is declaring a new intger inside a loop changes the space complexity of the metohd?
for exampe if i'm looking at the follwoing 2 methods, is both of the methods space complexity is O(1)? or in the first method becuase I'm declaring the variable c over and over until the loop end it's space complexity is O(n)?
public static int what (int []a) {
int temp = 0;
for (int i = 0; i < a.length; i++) {
for (int j = i; j < a.length; j++) {
**int c = f(a, i, j);**
if (c % 2 == 0) {
if (j - i + 1 > temp)
temp = j - i + 1;
}
}
}
return temp;
}
public static int what (int []a) {
int temp = 0;
**int c;**
for (int i = 0; i < a.length; i++) {
for (int j = i; j < a.length; j++) {
**c = f(a, i, j);**
if (c % 2 == 0) {
if (j - i + 1 > temp)
temp = j - i + 1;
}
}
}
return temp;
}
Not sure if it's relevant to the question but also attahced the f method.
private static int f (int[]a, int low, int high)
{
int res = 0;
for (int i=low; i<=high; i++)
res += a[i];
return res;
}

When you declare a variable inside the for loop it goes out of scope when the iteration ends and gets re declared in the next iteration so you are not declaring n variables, you are declaring a variable n times

Related

Finding number of pairs, product of whose indices is divisible by another number X

Given an array and some value X, find the number of pairs such that i < j , a[i] = a[j] and (i * j) % X == 0
Array size <= 10^5
I am thinking of this problem for a while but only could come up with the brute force solution(by checking all pairs) which will obviously time-out [O(N^2) time complexity]
Any better approach?
First of all, store separate search structures for each distinct A[i] as we iterate.
i * j = k * X
i = k * X / j
Let X / j be some fraction. Since i is an integer, k would be of the form m * least_common_multiple(X, j) / X, where m is natural.
Example 1: j = 20, X = 60:
lcm(60, 20) = 60
matching `i`s would be of the form:
(m * 60 / 60) * 60 / 20
=> m * q, where q = 3
Example 2: j = 6, X = 2:
lcm(2, 6) = 6
matching `i`s would be of the form:
(m * 6 / 2) * 2 / 6
=> m * q, where q = 1
Next, I would consider how to efficiently query the number of multiples of a number in a sorted list of arbitrary naturals. One way is to hash the frequency of divisors of each i we add to the search structure of A[i]. But first consider i as j and add to the result the count of divisors q that already exist in the hash map.
JavaScript code with brute force testing at the end:
function gcd(a, b){
return b ? gcd(b, a % b) : a;
}
function getQ(X, j){
return X / gcd(X, j);
}
function addDivisors(n, map){
let m = 1;
while (m*m <= n){
if (n % m == 0){
map[m] = -~map[m];
const l = n / m;
if (l != m)
map[l] = -~map[l];
}
m += 1;
}
}
function f(A, X){
const Ais = {};
let result = 0;
for (let j=1; j<A.length; j++){
if (A[j] == A[0])
result += 1;
// Search
if (Ais.hasOwnProperty(A[j])){
const q = getQ(X, j);
result += Ais[A[j]][q] || 0;
// Initialise this value's
// search structure
} else {
Ais[A[j]] = {};
}
// Add divisors for j
addDivisors(j, Ais[A[j]]);
}
return result;
}
function bruteForce(A, X){
let result = 0;
for (let j=1; j<A.length; j++){
for (let i=0; i<j; i++){
if (A[i] == A[j] && (i*j % X) == 0)
result += 1;
}
}
return result;
}
var numTests = 1000;
var n = 100;
var m = 50;
var x = 100;
for (let i=0; i<numTests; i++){
const A = [];
for (let j=0; j<n; j++)
A.push(Math.ceil(Math.random() * m));
const X = Math.ceil(Math.random() * x);
const _brute = bruteForce(A, X);
const _f = f(A, X);
if (_brute != _f){
console.log("Mismatch!");
console.log(X, JSON.stringify(A));
console.log(_brute, _f);
break;
}
}
console.log("Done testing.")
Just in case If someone needed the java version of this answer - https://stackoverflow.com/a/69690416/19325755 explanation has been provided in that answer.
I spent lot of time in understanding the javascript code so I thought the people who are comfortable with java can refer this for better understanding.
import java.util.HashMap;
public class ThisProblem {
public static void main(String[] args) {
int t = 1000;
int n = 100;
int m = 50;
int x = 100;
for(int i = 0; i<t; i++) {
int[] A = new int[n];
for(int j = 0; j<n; j++) {
A[j] = ((int)Math.random()*m)+1;
}
int X = ((int)Math.random()*x)+1;
int optR = createMaps(A, X);
int brute = bruteForce(A, X);
if(optR != brute) {
System.out.println("Wrong Answer");
break;
}
}
System.out.println("Test Completed");
}
public static int bruteForce(int[] A, int X) {
int result = 0;
int n = A.length;
for(int i = 1; i<n; i++) {
for(int j = 0; j<i; j++) {
if(A[i] == A[j] && (i*j)%X == 0)
result++;
}
}
return result;
}
public static int gcd(int a, int b) {
return b==0 ? a : gcd(b, a%b);
}
public static int getQ(int X, int j) {
return X/gcd(X, j);
}
public static void addDivisors(int n, HashMap<Integer, Integer> map) {
int m = 1;
while(m*m <= n) {
if(n%m == 0) {
map.put(m, map.getOrDefault(m, 0)+1);
int l = n/m;
if(l != m) {
map.put(l, map.getOrDefault(l, 0)+1);
}
}
m++;
}
}
public static int createMaps(int[] A, int X) {
int result = 0;
HashMap<Integer, HashMap<Integer, Integer>> contentsOfA = new HashMap<>();
int n = A.length;
for(int i = 1; i<n; i++) {
if(A[i] == A[0])
result++;
if(contentsOfA.containsKey(A[i])) {
int q = getQ(X, i);
result += contentsOfA.get(A[i]).getOrDefault(q, 0);
} else {
contentsOfA.put(A[i], new HashMap<>());
}
addDivisors(i, contentsOfA.get(A[i]));
}
return result;
}
}

Time complexity single loop with two variables

What will be the time complexity of below code and why?
public static int[] Shuffle(int[] nums, int n)
{
int len = nums.Length;
int[] final = new int[2 * n];
int counter = 0;
for (int i = 0, j = n; i < n; i++, j++)
{
final[counter++] = nums[i];
final[counter++] = nums[j];
}
return final;
}
If we will have two loops as below then it will be considered as time complexity of O(n^2)
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
}
}
Complexity is O(n) because the cursor is looping from i = 0 until i = n-1. Number of variables doesn't matter when it comes to time complexity. (there is space complexity as well) However care,
for (int i = 0, j = n; i < n; i++, j++)
is completely different from
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{

Is this algorithm for the function correct?

The question I'm trying to solve is...
What is the value returned by the following function? Express your answer as a function of n.
int v = 0;
int n = 100;
for (int i = 1; i <= n ; i++)
{
for( int j = n + 1; j < 2 * n; j++)
{
v = v + 1;
}
}
System.out.println(v);
Seems like I'm missing something but I don't know what. =/ Thank you.
I don't want to give the whole answer away.
First of, our function looks like this.
int v = 0;
for (int i = 1; i <= n; i++) {
for (int j = (n + 1); j <= (n*2); j++) {
v++;
}
}
System.out.println(v);
So, depending on n what will v give us?
Let's try it, let's try for n = 1 to 20
for (int n = 1; n < 20; n++) {
int v = 0;
for (int i = 1; i <= n; i++) {
for (int j = (n + 1); j <= (n*2); j++) {
v++;
}
}
System.out.println(v);
}
Try that! If you still are curious give a poke here.
Hint #2. It is a very specific function, a very common.

Count null diagonals in a matrix

I'm trying to create a program that counts the number of null diagonals in a square matrix, but I can't seem to find the correct way of making my index run correctly through the matrix. Here's the incorrect code I've got so far:
# include<stdio.h>
# define MAX 100
int DiagonNull (int n, int A[MAX][MAX]) {
int i, j, count, null;
banda = 0;
for(i = n - 1; i >= 0; i--){
count = 0;
for(j = 0; j <= n && j < i - 1; j++){
if (A[i][j] == 0)
count++;
}
if (count == n - i) /* n - i = number of elements in diagonal */
null++;
else
i = - 1;
}
return null;
}
int main () {
int n, A[MAX][MAX], i, j, null;
printf ("Enter value of n to create a square matrix A of order n: ");
scanf ("%d", &n);
printf ("Enter the elements of matrix A: ");
for (i = 0; i < n; i++){
for (j = 0; j < n; j++){
scanf("%d", &A[i][j]);
}
}
null = DiagonNull (n, A);
printf ("Matrix has null %d diagonals", null);
return 0;
}

Number of binary trees with equal values

There is array of values:
1 - n_1 times
2 - n_2 times
...
k - n_k times
How many trees with this nodes exist?
I create simple algorythm:
int get_count(const vector<int> n_i) {
if (n_i.size() <= 1) {
return 1;
} else {
int total_count = 0;
for (int i = 0; i < n_i.size(); ++i) {
vector<int> first;
vector<int> second;
for (int j = 0; j < i; ++j) {
first.push_back(n_i[j]);
}
if (n_i[i] != 1) {
second.push_back(n_i[i] - 1);
}
for (int j = i + 1; j < n_i.size(); ++j) {
second.push_back(n_i[j]);
}
total_count += (get_count(first) * get_count(second));
}
return total_count;
}
}
Because
#(n_1, n_2, ... n_k) = #(n_1 - 1, n_2, ..., n_k) + #(n_1) #(n_2 - 1, ... n_k) + ... + #(n_1, ..., n_k - 1)
and
#(0, n_i, n_j, ...) = #(n_i, n_j, ...)
But my code is so slow.
Is there a final formula via Cathalan's numbers, for example?
I guess that the problem can be split into calculating the number of permutations and calculating the number of binary trees of given size. I converted my initial recursive Java code (which gives up on n1=10,n2=10,n3=10) into this iterative one:
static int LIMIT = 1000;
static BigInteger[] numberOfBinaryTreesOfSize = numberOfBinaryTreesBelow(LIMIT);
static BigInteger[] numberOfBinaryTreesBelow(int m) {
BigInteger[] arr = new BigInteger[m];
arr[0] = BigInteger.ZERO;
arr[1] = arr[2] = BigInteger.ONE;
for (int n = 3; n < m; n++) {
BigInteger s = BigInteger.ZERO;
for (int i = 1; i < n; i++)
s = s.add(arr[i].multiply(arr[n - i]));
arr[n] = s;
}
return arr;
}
static BigInteger[] fac = facBelow(LIMIT);
static BigInteger[] facBelow(int m) {
BigInteger[] arr = new BigInteger[m];
arr[0] = arr[1] = BigInteger.ONE;
for (int i = 2; i < m; i++)
arr[i] = arr[i - 1].multiply(BigInteger.valueOf(i));
return arr;
}
static BigInteger getCountFast(int[] arr) {
// s: sum of n_i
int s = 0; for (int i = 0; i < arr.length; i++) { s += arr[i]; }
// p: number of permutations
BigInteger p = fac[s]; for (int i = 0; i < arr.length; i++) { p = p.divide(fac[arr[i]]); }
BigInteger count = p.multiply(numberOfBinaryTreesOfSize[s]);
return count;
}
public static void main(String[] args) {
System.out.println(getCountFast(new int[]{ 150, 150, 150, 150, 150 }));
}
The LIMIT limits the sum of the n_i. The above example takes about two seconds on my machine. Maybe it helps you with a C++ solution.

Resources