Modify LinkedList after traverse - java

I am using a LinkedList, I need to add an element to the LinkedList immediately after traversing it.
I mean, let's suppose I have a LinkedList of unsorted integers.
LinkedList<Integer> list = new LinkedList<>();
list.add(4);
list.add(2);
list.add(5);
I want to add a zero after each even number.
var itr = list.listIterator();
while (itr.hasNext()) {
int i = itr.next();
if (i % 2 == 0) {
itr.add(0);
}
}
After executing this, I get the LinkedList containing: [4, 0, 2, 0, 5]
Now suppose I want to add a zero only after the smallest even number.
I know I can first search the smallest even number traversing the LinkedList in O(n) and then using the .add(index, element) to add the zero after the smallest even number. The add(index, element) method runs in average O(n) since it needs to traverse some nodes of the list, I would like to avoid it and perform my operation of adding a zero after the smallest even number in a single traverse. Is that possible?
Update
Thanks so much guys for your answers. I'll try to write a pseudocode, I think if I was working with a custom double linked list the problem could be solved in the following way
Node smallest = new Node(99998); // reference to smallest even number
While (current != Null){
If (current.value %2 == 0 && current.value < smallest.value){
smallest = current:
}
current = current.next:
}
// Link zero after smallest even number in constant time
Node zero = new Node (0);
zero.prev = smallest;
zero.next = smallest.next;
smallest.next = zero:
smallest.next.prev = zero;
Something like that. What do you think about it?

Though it might not be the most efficient, but you might use two iterators.
First for list traversal
Second for smallest numbers traversal
The issue is, when the smallest number is found, then the second iterator must catch up with the first iterator, so you end up calling Iterator#next() n-times, where n is difference between indices of the old and the new smallest number.
while (itr.hasNext()) {
int i = itr.next();
if (i % 2 == 0 && i < smallest) {
smallest = i;
while (smallestItr.nextIndex() != itr.previousIndex()) {
smallestItr.next();
}
}
}
System.out.println(smallestItr.next())
Otherwise, I would say if you need to put number into specified index in reasonable time complexity, use reasonable data structure for it.

Related

How can two or more lists be traversed in O(N)

I have a question that doesn't seem possible to me. I have 2+ arrays which I have to compare for common values. I am supposed to do this in O(N) comparisons but can't think of a way. Specifically (k-1)N comparisons where k is the number of arrays. I've narrowed down how I can take multiple arrays and just merge them into a single array. I've gotten that the smallest array is the limiting factor so if I sort that I can save the most comparisons. After spending half the day staring at my screen I've even come up with a way to do this linearly if I discount any duplicates, but I have to keep duplicates So, as far as I know in order to compare any arrays you need at least 2 for loops which would be O(N^2) wouldn't it? I'm also not allowed to hash anything.
For example if I had {1,3,4,3,4,5} as a master and {1,1,3,5,9,3,7} and {3,5,8,4,0,3,2} as arrays to be compared I'd need to have a final of {3,3,5} since I can't get rid of any dupiclates.
I don't want anyone to write the code, I just need to know what I should be doing in the first place.
Use an array of ints. Taking your first list, for each element, set the value at that index to 1. So if the first element is 3, put 1 in array[3]. Now, we know that 3 is present in first list. Putting 1 will help you distinguish from a 3 that is present in the earlier list versus a 3 which is repeated in current list.
Iterate through all the other k-1 lists
For every element, check the value in array for that index
If the value is 0, set it to this list number
If the value is a number less than this list number, this number is a duplicate and has already appeared in a previous list.
If this number is equal to this list index it means this number already occurred in this list but not in previous lists, so not yet a duplicate.
The numbers that you are getting as duplicates, add them to another list.
Finish all iterations
Finally print the duplicates.
Original Wrong Answer
Create a HashSet<int>
Take all values from master and add to it - O(master list count)
Now just iterate through first and second arrays and see if their elements are in that HashSet - O(each list count)
If the lists are sorted, then it's relatively straightforward if you do something like this:
List<Integer> intersection = new ArrayList<>();
int i = 0;
int j = 0;
while (i < list1.size() && j < list2.size()) {
int a = list1.get(i);
int b = list2.get(j);
if (a < b) {
i++;
} else if (b < a) {
j++;
} else { // a == b
intersection.add(a);
i++;
j++;
}
}
On each iteration of the loop, the quantity i + j increases by at least 1, and the loop is guaranteed to be done when i + j >= list1.size() + list2.size(), so the whole thing does at most O(list1.size() + list2.size()) comparisons.

Java, Finding Kth largest value from the array [duplicate]

This question already has answers here:
How to find the kth largest element in an unsorted array of length n in O(n)?
(32 answers)
Closed 7 years ago.
I had an interview with Facebook and they asked me this question.
Suppose you have an unordered array with N distinct values
$input = [3,6,2,8,9,4,5]
Implement a function that finds the Kth largest value.
EG: If K = 0, return 9. If K = 1, return 8.
What I did was this method.
private static int getMax(Integer[] input, int k)
{
List<Integer> list = Arrays.asList(input);
Set<Integer> set = new TreeSet<Integer>(list);
list = new ArrayList<Integer>(set);
int value = (list.size() - 1) - k;
return list.get(value);
}
I just tested and the method works fine based on the question. However, interviewee said, in order to make your life complex! lets assume that your array contains millions of numbers then your listing becomes too slow. What you do in this case?
As hint, he suggested to use min heap. Based on my knowledge each child value of heap should not be more than root value. So, in this case if we assume that 3 is root then 6 is its child and its value is grater than root's value. I'm probably wrong but what you think and what is its implementation based on min heap?
He has actually given you the whole answer. Not just a hint.
And your understanding is based on max heap. Not min heap. And it's workings are self-explanatory.
In a min heap, the root has the minimum (less than it's children) value.
So, what you need is, iterate over the array and populate K elements in min heap.
Once, it's done, the heap automatically contains the lowest at the root.
Now, for each (next) element you read from the array,
-> check if the value is greater than root of min heap.
-> If yes, remove root from min heap, and add the value to it.
After you traverse your whole array, the root of min heap will automtically contain the kth largest element.
And all other elements (k-1 elements to be precise) in the heap will be larger than k.
Here is the implementation of the Min Heap using PriorityQueue in java. Complexity: n * log k.
import java.util.PriorityQueue;
public class LargestK {
private static Integer largestK(Integer array[], int k) {
PriorityQueue<Integer> queue = new PriorityQueue<Integer>(k+1);
int i = 0;
while (i<=k) {
queue.add(array[i]);
i++;
}
for (; i<array.length; i++) {
Integer value = queue.peek();
if (array[i] > value) {
queue.poll();
queue.add(array[i]);
}
}
return queue.peek();
}
public static void main(String[] args) {
Integer array[] = new Integer[] {3,6,2,8,9,4,5};
System.out.println(largestK(array, 3));
}
}
Output: 5
The code loop over the array which is O(n). Size of the PriorityQueue (Min Heap) is k, so any operation would be log k. In the worst case scenario, in which all the number are sorted ASC, complexity is n*log k, because for each element you need to remove top of the heap and insert new element.
Edit: Check this answer for O(n) solution.
You can probably make use of PriorityQueue as well to solve this problem:
public int findKthLargest(int[] nums, int k) {
int p = 0;
int numElements = nums.length;
// create priority queue where all the elements of nums will be stored
PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
// place all the elements of the array to this priority queue
for (int n : nums){
pq.add(n);
}
// extract the kth largest element
while (numElements-k+1 > 0){
p = pq.poll();
k++;
}
return p;
}
From the Java doc:
Implementation note: this implementation provides O(log(n)) time for
the enqueing and dequeing methods (offer, poll, remove() and
add); linear time for the remove(Object) and contains(Object)
methods; and constant time for the retrieval methods (peek,
element, and size).
The for loop runs n times and the complexity of the above algorithm is O(nlogn).
Heap based solution is perfect if the number of elements in array/stream is unknown. But, what if they are finite but still you want an optimized solution in linear time.
We can use Quick Select, discussed here.
Array = [3,6,2,8,9,4,5]
Let's chose the pivot as first element:
pivot = 3 (at 0th index),
Now partition the array in such a way that all elements less than or equal are on left side and numbers greater than 3 on right side. Like it's done in Quick Sort (discussed on my blog).
So after first pass - [2,3,6,8,9,4,5]
pivot index is 1 (i.e it's the second lowest element). Now apply the same process again.
chose, 6 now, the value at index after previous pivot - [2,3,4,5,6,8,9]
So now 6 is at the proper place.
Keep checking if you have found the appropriate number (kth largest or kth lowest in each iteration). If it's found you are done else continue.
One approach for constant values of k is to use a partial insertion sort.
(This assumes distinct values, but can easily be altered to work with duplicates as well)
last_min = -inf
output = []
for i in (0..k)
min = +inf
for value in input_array
if value < min and value > last_min
min = value
output[i] = min
print output[k-1]
(That's pseudo code, but should be easy enough to implement in Java).
The overall complexity is O(n*k), which means it works pretty well if and only if k is constant or known to be less that log(n).
On the plus side, it is a really simple solution. On the minus side, it is not as efficient as the heap solution

Finding a powerset from a linked list

I am looking for some help with my Java programming assignment. Using a linked list, I need to print out its power set. For example, the set {1,2,3} should print out
{{},{1}{1,2}{1,3}{1,2,3}{2}{2,3}{3}}. The number of elements in the power set is 2^n.
This needs to be done by calling
HeadNode.PrintPowerSet();
where HeadNode is the first element in the linked list.
I have tried a few things and nothing is working that well. I think the best way to do it would be to call the method recursively until the end sentinel is reached and then work backwards, adding the elements that are left. Sorry I can't post more code or more ideas because nothing I have tried has worked that well. Thanks in advance.
EDIT:
This is the non working code. It returns the set {{1,2,3}{2,3}{3}}
public RSet powerSet()
{
if (this == EMPTY_SET)
return EMPTY_SET;
RSet q = new RSet();
if (q != EMPTY_SET)
q.next = next.powerSet();
q = new RSet(this, n, q.next);
return q;
}
EMPTY_SET is the end sentinel. I've tried writing it out by hand. It helps but I still can't get it. Also this class, RSet, is essentially just a linked list node.
Just iterate all the numbers from 0 to 2^n - 1. Each defines an element of the power set:
The list defines a fixed index on your set. For each number, create a new set. Considering the number in its binary format, add the item in the original set at index i to the set if the bit at index i is 1 and don't add it otherwise.
Then, for each number you will have a set that is an element of the power set.
int n = list.size();
Set<Set<T>> powerSet = new HashSet<Set<T>>();
for( long i = 0; i < (1 << n - 1); i++) {
Set<T> element = new HashSet<T>();
for( int j = 0; j < n; j++ )
if( (i >> j) % 2 == 1 ) element.add(list.get(j));
powerSet.add(element);
}
return powerSet;

Java: LinkedList reversal in chunks

If you are provided the head of a linked list, and are asked to reverse every k sequence of nodes, how might this be done in Java? e.g., a->b->c->d->e->f->g->h with k = 3 would be c->b->a->f->e->d->h->g->f
Any general help or even pseudocode would be greatly appreciated! Thanks!
If k is expected to be reasonably small, I would just go for the simplest thing: ignore the fact that it's a linked list at all, and treat each subsequence as just an array-type thing of things to be reversed.
So, if your linked list's node class is a Node<T>, create a Node<?>[] of size k. For each segment, load k Nodes into the array list, then just reverse their elements with a simple for loop. In pseudocode:
// reverse the elements within the k nodes
for i from 0 to k/2:
nodeI = segment[i]
nodeE = segment[segment.length-i-1]
tmp = nodeI.elem
nodeI.elem = nodeE.elem
nodeE.elem = tmp
Pros: very simple, O(N) performance, takes advantage of an easily recognizable reversing algorithm.
Cons: requires a k-sized array (just once, since you can reuse it per segment)
Also note that this means that each Node doesn't move in the list, only the objects the Node holds. This means that each Node will end up holding a different item than it held before. This could be fine or not, depending on your needs.
This is pretty high-level, but I think it'll give some guidance.
I'd have a helper method like void swap3(Node first, Node last) that take three elements at an arbitrary position of the list and reverses them. This shouldn't be hard, and could could be done recursively (swap the outer elements, recurse on the inner elements until the size of the list is 0 or 1). Now that I think of it, you could generalize this into swapK() easily if you're using recursion.
Once that is done, then you can just walk along your linked list and call swapK() every k nodes. If the size of the list isn't divisble by k, you could either just not swap that last bit, or reverse the last length%k nodes using your swapping technique.
TIME O(n); SPACE O(1)
A usual requirement of list reversal is that you do it in O(n) time and O(1) space. This eliminates recursion or stack or temporary array (what if K==n?), etc.
Hence the challenge here is to modify an in-place reversal algorithm to account for the K factor. Instead of K I use dist for distance.
Here is a simple in-place reversal algorithm: Use three pointers to walk the list in place: b to point to the head of the new list; c to point to the moving head of the unprocessed list; a to facilitate swapping between b and c.
A->B->C->D->E->F->G->H->I->J->L //original
A<-B<-C<-D E->F->G->H->I->J->L //during processing
^ ^
| |
b c
`a` is the variable that allow us to move `b` and `c` without losing either of
the lists.
Node simpleReverse(Node n){//n is head
if(null == n || null == n.next)
return n;
Node a=n, b=a.next, c=b.next;
a.next=null; b.next=a;
while(null != c){
a=c;
c=c.next;
a.next=b;
b=a;
}
return b;
}
To convert the simpleReverse algorithm to a chunkReverse algorithm, do following:
1] After reversing the first chunk, set head to b; head is the permanent head of the resulting list.
2] for all the other chunks, set tail.next to b; recall that b is the head of the chunk just processed.
some other details:
3] If the list has one or fewer nodes or the dist is 1 or less, then return the list without processing.
4] use a counter cnt to track when dist consecutive nodes have been reversed.
5] use variable tail to track the tail of the chunk just processed and tmp to track the tail of the chunk being processed.
6] notice that before a chunk is processed, it's head, which is bound to become its tail, is the first node you encounter: so, set it to tmp, which is a temporary tail.
public Node reverse(Node n, int dist) {
if(dist<=1 || null == n || null == n.right)
return n;
Node tail=n, head=null, tmp=null;
while(true) {
Node a=n, b=a.right; n=b.right;
a.right=null; b.right=a;
int cnt=2;
while(null != n && cnt < dist) {
a=n; n=n.right; a.right=b; b=a;
cnt++;
}
if(null == head) head = b;
else {
tail.right=b;tail=tmp;
}
tmp=n;
if(null == n) return head;
if(null == n.right) {
tail.right=n;
return head;
}
}//true
}
E.g. by Common Lisp
(defun rev-k (k sq)
(if (<= (length sq) k)
(reverse sq)
(concatenate 'list (reverse (subseq sq 0 k)) (rev-k k (subseq sq k)))))
other way
E.g. by F# use Stack
open System.Collections.Generic
let rev_k k (list:'T list) =
seq {
let stack = new Stack<'T>()
for x in list do
stack.Push(x)
if stack.Count = k then
while stack.Count > 0 do
yield stack.Pop()
while stack.Count > 0 do
yield stack.Pop()
}
|> Seq.toList
Use a stack and recursively remove k items from the list, push them to the stack then pop them and add them in place. Not sure if it's the best solution, but stacks offer a proper way of inverting things. Notice that this also works if instead of a list you had a queue.
Simply dequeue k items, push them to the stack, pop them from the stack and enqueue them :)
This implementation uses ListIterator class:
LinkedList<T> list;
//Inside the method after the method's parameters check
ListIterator<T> it = (ListIterator<T>) list.iterator();
ListIterator<T> reverseIt = (ListIterator<T>) list.listIterator(k);
for(int i = 0; i< (int) k/2; i++ )
{
T element = it.next();
it.set(reverseIt.previous());
reverseIt.set(element);
}

Figuring out if all but one array elements are identical

Does anyone know how I would work out if all elements in an array but one have the same value?
I have been trying to work it out for ages but cannot solve it. For example testing an array that has 5 elements to see if it has 4 identical values.
Thanks
Use a map.
Map<X, Integer> map = new HashMap<X, Integer>(); // where X is the array type
Integer ct;
for(X item : array){
ct = map.get(item);
if(ct == 0) ct = Integer.valueOf(1);
else ct = Integer.valueOf(ct.intValue()+1);
map.put(item, ct);
}
// now test if map.values() consists of Integer.valueOf(1) and (optionally)
// another positive integer (thx aioobe)
Step by Step:
Get the first element.
Loop all the array elements and count the number of times they don't
match that first element.
If all of the elements match, you have your answer (all are equal).
If only one of the elements do not match, you have your answer (one
is different).
If some of the elements do not match, you have your answer (more than
one is different).
In none of the elements match, get the second element and repeat the
test.
If only one of the elements do not match, again only one is different (the first one).
Else, the number of different elements is bigger than one.
The approach I would choose is:
iterate over all elements and put them in a Map (HashMap in Java).
the key is the element, and the value is the counter of the appearance.
example: your array: A A A A B
map:
A -> 4
B -> 1
After you have constructed that map it's easy to find out if your array matches that criteria.
The map must have exactly 2 elements (map.size()).
Exactly one of the elements has the counter 1.
If you assume that adding to a map happens in constant time you'll have an overall complexity of 2n (iterate over array and iterate over map).
I came up with this trick :-)
public static boolean allButOneSame(int[] arr) {
if (arr.length <= 1)
return arr.length == 1;
Arrays.sort(arr);
return arr[0] != arr[arr.length-1] &&
(arr[0] == arr[arr.length-2] ||
arr[1] == arr[arr.length-1]);
}
(Relies on comparable values such as integers though!)
Iterate array, by comparing 1st element and x+1 elements where x is 2,3,4,...array.length()
If comparison fails then increment a counter
if ((counter==0) || ((counter> 1) && (counter != array.length-1))) then condition is not met
counter=0 means, all are same elements
counter=array.length-1 means sorted order eg: 4,5,5,5,5,5,5
Complexity ->time: O(n), no extra space other than counter
Here's another approach:
public static <Item> boolean allButOneSame(List<Item> items) {
// Make sure we have 2 different elements (or 1 element in total)
if (new HashSet<Item>(items).size() != 2)
return items.size() == 1;
// Create a temporary copy
List<Item> tmp = new ArrayList<Item>(items);
// Remove all elements equal to the first one.
tmp.removeAll(Collections.singleton(items.get(0)));
// Check the number of remaining elements.
return tmp.size() == 1 || tmp.size() == items.size() - 1;
}
It takes a List as input. Use Arrays.asList if start with an array.
You could also add all array elements into a LinkedHashSet (no duplicates, insertion order is preserved) and look at the set's .size()

Categories