Sum of length between nodes in a vector - c++

I have the following Task: I am doing an implementation of the Cheapest Insertion method and I am storing my subtours into a vector. After building the vector, I Need to find the total length of the distances between the nodes, that are included in the vector (for example I have 0-32-41-3-45-0 stored in the vector). How can I calculate the total distance? I have the following function:
double tLength = 0;
for (vector<int>::iterator i=resultingRoute.begin(); i!=resultingRoute.end();i++)
{
tLength+= distanceMatrix[*i][*i+1];
}
return tLength;
but it is calculating from 0 to 1, then from 32 to 33, 41 to 42, and so on. What I Need is 0 to 32, 32 to 41, 41 to 3. I tried to create a second iterator j to start at.begin()+1, but it is repeating the second part of the function too much.
double tLength = 0;
for (vector<int>::iterator i=resultingRoute.begin(); i!=resultingRoute.end()-1;i++)
{
for(vector<int>::iterator j=resultingRoute.begin()+1;j!=resultingRoute.end();j++)
{
tLength+= distanceMatrix[*i][*j];
}
}
return tLength;
What is the best way to calculate the length of the tour? Thanks.

but it is calculating from 0 to 1, then from 32 to 33, 41 to 42, and
so on
It indeed does it as the *i+1 takes value of *i and adds a 1 to it. You probably wanted to write *(i+1). In that case the condition i!=resultingRoute.end() is incorrect, it should be i!=resultingRoute.end()-1, otherwise the *(i+1) would be out of range for last element. You should also check whether the vector has at least 2 elements before entering the loop.
You can avoid the iterators and work with the vector as if it were an array, without the need to check the vector's size:
for (size_t i = 0; i + 1 < resultingRoute.size(); ++i)
tLength += distanceMatrix[resultingRoute[i]][resultingRoute[i+1]];

Related

C++ lambda expression for sort follows relative ordering

I solved a leetcode problem 2191. Sort the Jumbled Numbers. My doubt is why my code is able to maintain the relative ordering in sorting when mapped values of the elements are equal. Here is the Leetcode question description:
You are given a 0-indexed integer array mapping which represents the mapping rule of a shuffled decimal system. mapping[i] = j means digit i should be mapped to digit j in this system.
The mapped value of an integer is the new integer obtained by replacing each occurrence of digit i in the integer with mapping[i] for all 0 <= i <= 9.
You are also given another integer array nums. Return the array nums sorted in non-decreasing order based on the mapped values of its elements.
Notes:
Elements with the same mapped values should appear in the same relative order as in the input.
The elements of nums should only be sorted based on their mapped values and not be replaced by them.
Example 1
Input: mapping = [8,9,4,0,2,1,3,5,7,6], nums = [991,338,38]
Output: [338,38,991]
Explanation:
Map the number 991 as follows:
1. mapping[9] = 6, so all occurrences of the digit 9 will become 6.
2. mapping[1] = 9, so all occurrences of the digit 1 will become 9.
Therefore, the mapped value of 991 is 669.
338 maps to 007, or 7 after removing the leading zeros.
38 maps to 07, which is also 7 after removing leading zeros.
Since 338 and 38 share the same mapped value, they should remain in the same relative order, so 338 comes before 38.
Thus, the sorted array is [338,38,991].
Example 2
Input: mapping = [0,1,2,3,4,5,6,7,8,9], nums = [789,456,123]
Output: [123,456,789]
Explanation: 789 maps to 789, 456 maps to 456, and 123 maps to 123. Thus, the sorted array is [123,456,789].
My Accepted C++ Code
class Solution {
public:
// function for converting a given number n according to mapped values
int calculate(int n, vector<int>& map){
int ans = 0, mul = 1;
if(n == 0)
return map[0];
while(n != 0){
int digit = n % 10;
ans += map[digit] * mul;
mul *= 10;
n /= 10;
}
return ans;
}
vector<int> sortJumbled(vector<int>& mapping, vector<int>& nums) {
// C++ lambda expression added inside sort function
sort(begin(nums), end(nums), [&](int x , int y){
return calculate(x, mapping) < calculate(y, mapping);
});
return nums;
}
};
My Doubt
Let me take the Example 1, where nums = [991,338,38] and it's corresponding mapped values = [669, 7, 7]. Here the expected output is [338,38,991] and my code is working correctly. My doubt is that why 338 is coming first in the output as my lambda expression only checking a < b condition. So whenever a < b is true, then a comes first in the sorted order otherwise b comes. According to my code what I think is that when calculate(338, mapping) < calculate(38, mapping) is called, it returns false right? So 38 should come first right? Can someone please explain how my code is doing the stable sort when elements have equal mapped values.

How to compare all elements of vector one to vector two and if a max element exists then comparing all the elements of vector two to vector three?

I want to compare all element of vector x to all elements of vector y and if I find a element greater in vector y than being compared to, I have to take that particular element of vector y and compare to all elements of vector z and if it is true return true else if i don't find a greater element in first iteration i,e when elements of vector x are compared to vector y i have to break the loop and return false.
I tried to iterate through all the elements of stackarmies but I don't know how to take the first element of vector one and compare with all the elements of vector, since all the vectors are merged into the last vector.
vector<int> stack;
int noofstack, noofoperations, stackno, OperationType;
// Taking the input number of stacks
cin >> noofstack;
vector<vector<int>> stackarmies;
for (int i = 0; i < noofstack; i++)
{
int stacksize;
//Since vectors are dynamic and we don't need to declare the size but as per the problem statement I've added it/
cin >> stacksize;
for (int k = 0; k < stacksize; k++)
{
//Taking the input of all the vectors one by one and then adding all the vectors into one vector
int armyheight;
cin>>armyheight;
stack.push_back(armyheight);
}
stackarmies.push_back(stack);
Test cases
Input 1
2
3 3 5 4
3 1 1 2
Resulting stackarmies: { {3, 5, 4}, {3, 5, 4, 1, 1, 2} }
Desired output: False
We will take first element of vector 1 : 3 and compare with all
elements of vector 2 , in vector 2 no element is greater than 3.
Input 2
2
3 1 0 4
3 2 1 3
Resulting stackarmies: { {1, 0, 4}, {1, 0, 4, 2, 1, 3} }
Desired output: True
We will take first element of vector 1 : 1 and compare with all
elements of vector 2, in vector 2, the first element is greater than 1,
so true
Input 3
2
3 1 9 0
2 0 11
Resulting stackarmies: { {1, 9, 0}, {1, 9, 0, 0, 11} }
Desired output: True
We will take first element of vector 1 : 1 and compare with all
elements of vector 2, in vector 2, the last element is greater than 1,
so true
Input 4
3
3 0 8 0
3 4 0 11
3 0 9 0
Resulting stackarmies: { {0, 8, 0}, {0, 8, 0, 4, 0, 11} , {0, 8, 0, 4, 0, 11, 0, 9, 0} }
Desired output: True
We will take the second element of vector 1: 8 and compare with
all elements of vector 2 , 11 is greater than 8 so we will compare 11 of
vector 2 with vector , since there are no values greater than 11, so it's
false
I don't know how to take the first element of vector one and compare with all the elements of vector, since all the vectors are merged into the last vector.
You're getting ahead of yourself. Why do you want all the vectors merged into the last vector? Answer: you don't; that's just what happened. Why did all the vectors merge into the last vector? Answer: because you have a bug in your code that reads the data. Fix that bug instead of spending ten times as much effort trying to handle the malformed data.
That whole spiel about what you intend to do next is nothing more than a distraction that wastes the time of the people from whom you are asking help. Ask for help with the real problem (the loading bug) instead of driving people away with a confusing question that assumes bad data is good.
There are several ways to fix the bug. I think the most helpful approach is one that would have avoided the bug in the first place. You try to do too much in a single function. Divide and conquer; when you have a non-trivial sub-step, create a function to handle it. Good programming practices lead to fewer bugs.
Specifically, reading the heights of the fighters in a stack is non-trivial. Delegate that to a helper and reduce the body of your outer for loop to a single line.
for (int i = 0; i < noofstack; i++)
{
//* This is non-trivial, so use a helper function.
stackarmies.push_back(read_fighter_heights());
}
This helper function is responsible for reading a line of data, generating a stack (a vector<int>) from it, and returning that stack. That covers most of the body of your loop, leaving only the simple task of pushing the returned stack onto your vector of stacks.
Creating this helper function from your existing code is fairly simple. Mostly, just move the body of the loop into an appropriate function definition. In addition, you should notice that stack is needed (only) in this function, so also move that variable's declaration into the new function's definition.
vector<int> read_fighter_heights()
{
vector<int> stack;
int stacksize;
//Since vectors are dynamic and we don't need to declare the size but as per the problem statement I've added it/
cin >> stacksize;
for (int k = 0; k < stacksize; k++)
{
//Taking the input of all the vectors one by one and then adding all the vectors into one vector
int armyheight;
cin>>armyheight; //* Reading a single integer is trivial, so no need for another function here.
stack.push_back(armyheight);
}
return stack;
}
Presto! Problem solved. All you had to do was be more organized.
Addendum: The reason this solves the problem is that extra step of moving the declaration of stack. In the original code, this variable was declared outside the outer loop, and it was never cleared. The result was that it accumulated values from each line that was read. In this version, the variable is re-initialized before reading each line, so values do not accumulate. You could get the same result by moving the line in the original code, without splitting off a new function. However, splitting off a new function is a good habit to get into, as it almost forces you to declare stack at the right level, avoiding the problem in the first place.
bool CompareVectors(vector<vector<int>> st)
{
bool result = true;
for (int k = 0; k < st.size(); k++)
{
if (k != st.size() - 1)
{
if (result)
{
for (auto i = st[k].begin(); i != st[k].end(); ++i)
{
for (auto j = st[k+1].begin(); j != st[k+1].end(); ++j)
{
if (*i < *j)
{
result = true;
break;
}
else
{
result = false;
}
}
if (result)
{
break;
}
}
}
}
}
return result;
}

minimum total move to balance array if we can increase/decrease a specific array element by 1

It is leetcode 462.
I have one algorithm but it failed some tests while passing others.
I tried to think through but not sure what is the corner case that i overlooked.
We have one array of N elements. One move is defined as increasing OR decreasing one single element of the array by 1. We are trying to find the minimum number of moves to make all elements equal.
My idea is:
1. find the average
2. find the element closest to the average
3. sum together the difference between each element and the element closest to the average.
What am i missing? Please provide one counter example.
class Solution {
public:
int minMoves2(vector<int>& nums) {
int sum=0;
for(int i=0;i<nums.size();i++){
sum += nums[i];
}
double avg = (double) sum / nums.size();
int min = nums[0];
int index =0 ;
for(int i=0;i<nums.size();i++){
if(abs(nums[i]-avg) <= abs(min - avg)){
min = nums[i];
index = i;
}
}
sum=0;
for(int i=0;i<nums.size();i++){
sum += abs(min - nums[i]);
}
return sum;
}
};
Suppose the array is [1, 1, 10, 20, 100]. The average is a bit over 20. So your solution would involving 19 + 19 + 10 + 0 + 80 moves = 128. What if we target 10 instead? Then we have 9 + 9 + 0 + 10 + 90 moves = 118. So this is a counter example.
Suppose you decide to target changing all array elements to some value T. The question is, what's the right value for T? Given some value of T, we could ask if increasing or decreasing T by 1 will improve or worsen our outcome. If we decrease T by 1, then all values greater than T need an extra move, and all those below need one move less. That means that if T is above the median, there are more values below it than above, and so we benefit from decreasing T. We can make the opposite argument if T is less than the median. From this we can conclude that the correct value of T is actually the median itself, which my example demonstreates (strictly speaking, when you have an even sized array, T can be anywhere between the two middle elements).

Improving the time complexity in priority queue in c++

In the code below, I am getting time out for larger vector length, though it is working for smaller length vector.
long priceCalculate(vector < int > a, long k) {
long price = 0;
priority_queue<int>pq(a.begin(),a.end());
while(--k>=0){
int x = pq.top();
price = price + x;
pq.pop();
pq.push(x-1);
}
return price;
}
I have an array of numbers. I have to add the maximum number to price and then decrement that number by 1. Again find the maximum number and so on. I have to repeat this process for k times.
Is there any better data structure than priority queue which has less time complexity?
Below is the code using vector sort:
struct mclass {
public: bool operator()(int x, int y) {
return (x > y);
}
}
compare;
long priceCalculate(vector < int > a, long k) {
long price = 0;
sort(a.begin(), a.end(), compare);
while (--k >= 0) {
if (a[0] > 0) {
price = price + a[0];
a[0] = a[0] - 1;
sort(a.begin(), a.end(), compare);
}
}
return price;
}
But this is also giving timeout on large input length.
The sorting code has two performance problems:
You are resorting the vector<> in every iteration. Even if your sorting algorithm is insertion sort (which would be best in this case), it still needs to touch every position in the vector before it can declare the vector<> sorted.
To make matters worse, you are sorting the values you want to work with to the front of the vector, requiring the subsequent sort() call to shift almost all elements.
Consequently, you can achieve huge speedups by
Reversing the sort order, so that you are only interacting with the end of the vector<>.
Sort only once, then update the vector<> by scanning to the right position from the end, and inserting the new value there.
You can also take a closer look at what your algorithm is doing: It only ever operates on the tail of the vector<> which has constant value, removing entries from it, and reinserting them, decremented by one, in front of it. I think you should be able to significantly simplify your algorithm with that knowledge, leading to even more significant speedups. In the end, you can remove that tail from the vector<> entirely: It's completely described by its length and its value, and all its elements can be manipulated in a single operation. Your algorithm should take no time at all once you are through optimizing it...
For the vector solution you should be able to gain performance by avoiding sort inside the loop.
After
a[0] = a[0] - 1;
you can do something like the (pseudo) code below instead of calling sort:
tmp = 0;
for j = 1 to end-1
{
if a[0] < a[j]
++tmp
else
break
}
swap a[0], a[tmp]
to place the decremented value correctly in the sorted vector, i.e. since the vector is sorted from start, you'll only need to find the first element which is less or equal to the decremented value and swap the element just before with [0]. This should be faster than sort that has to go through the whole vector.
Examples of algorithm
// Vector after decremt
9, 10, 9, 5, 3, 2
^
tmp = 1
// Vector after swap
10, 9, 9, 5, 3, 2
// Vector after decremt
9, 10, 10, 5, 3, 2
^
tmp = 2
// Vector after swap
10, 10, 9, 5, 3, 2
Performance
I compared my approach with the vector example from OP:
k = 1000
vector.size = 10000000
vector filled with random numbers in range 0..9999
compiled with g++ -O3
My approach:
real 0.83
user 0.78
sys 0.05
OPs vector approach
real 119.42
user 119.42
sys 0.04

algorithm: find count of numbers within a given range

given an unsorted number array where there can be duplicates, pre-process the array so that to find the count of numbers within a given range, the time is O(1).
For example, 7,2,3,2,4,1,4,6. The count of numbers both >= 2 and <= 5 is 5. (2,2,3,4,4).
Sort the array. For each element in the sorted array, insert that element into a hash table, with the value of the element as the key, and its position in the array as the associated value. Any values that are skipped, you'll need to insert as well.
To find the number of items in a range, look up the position of the value at each end of the range in the hash table, and subtract the lower from the upper to find the size of the range.
This sounds suspiciously like one of those clever interview questions some interviewers like to ask, which is usually associated with hints along the way to see how you think.
Regardless... one possible way of implementing this is to make a list of the counts of numbers equal to or less than the list index.
For example, from your list above, generate the list: 0, 1, 3, 4, 6, 6, 7, 8. Then you can count the numbers between 2 and 5 by subtracting list[1] from list[5].
Since we need to access in O(1), the data structure needed would be memory-intensive.
With Hash Table, in worst case access would take O(n)
My Solution:
Build a 2D matrix.
array = {2,3,2,4,1,4,6} Range of numbers = 0 to 6 so n = 7
So we've to create nxn matrix.
array[i][i] represents total count of element = i
so array[4][4] = 2 (since 4 appears 2 times in array)
array[5][5] = 0
array[5][2] = count of numbers both >= 2 and <= 5 = 5
//preprocessing stage 1: Would populate a[i][i] with total count of element = i
a[n][n]={0};
for(i=0;i<=n;i++){
a[i][i]++;
}
//stage 2
for(i=1;i<=n;i++)
for(j=0;j<i;j++)
a[i][j] = a[i-1][j] + a[i][i];
//we are just adding count of element=i to each value in i-1th row and we get ith row.
Now (5,2) would query for a[5][2] and would give answer in O(1)
int main()
{
int arr[8]={7,2,3,2,4,1,4,6};
int count[9];
int total=0;
memset(count,0, sizeof(count));
for(int i=0;i<8;i++)
count[arr[i]]++;
for(int k=0;k<9;k++)
{
if(k>=2 && k<=5 && count[k]>0 )
{
total= total+count[k] ;
}
}
printf("%d:",total);
return 0;
}