Replace nodes in double linked list - java

Given two double linked lists I'm supposed to change, not just the elements, but the nodes of one of the lists so that the sum in the same positions equals a certain number.
public void repair(int num){
Node list1 = head1;
Node right = head2;
for(int i = 0; i<size; i++){
int element = num - list1.element;
Node p = right.previous;
Node s = right.next;
right = new Node(element, null, null);
p.next = right;
right.previous = p;
right.next = s;
s.previous = right;
list1 = list1.next;
right = right.next;
}
}
size = size of both list which is the same.
I've tried a lot of things but it always gives me nullpointerexception on p.next = right and s.previous = right;
I don't understand why it gives me this error. Can someone explain and show me a way of solving this?

It means p is null
Node p = right.previous;
Must be returning null
Seeing as right is defined as head2, you will have to look into head 2 and work out why head2.previous is null. I guess it is the beginning of the list or something.
You need to put null checks in so you only run operations on next / previous nodes when they are not null.

Related

MEX from root node to every other node in a tree

Given a rooted tree having N nodes. Root node is node 1. Each ith node has some value , val[i] associated with it.
For each node i (1<=i<=N) we want to know MEX of the path values from root node to node i.
MEX of an array is smallest positive integer not present in the array, for instance MEX of {1,2,4} is 3
Example : Say we are given tree with 4 nodes. Value of nodes are [1,3,2,8] and we also have parent of each node i (other than node 1 as it is the root node). Parent array is defined as [1,2,2] for this example. It means parent of node 2 is node 1, parent of node 3 is node 2 and parent of node 4 is also node 2.
Node 1 : MEX(1) = 2
Node 2 : MEX(1,3) = 2
Node 3 : MEX(1,3,2) = 4
Node 4 : MEX(1,3,8) = 2
Hence answer is [2,2,4,2]
In worst case total number of Nodes can be upto 10^6 and value of each node can go upto 10^9.
Attempt :
Approach 1 : As we know MEX of N elements will be always be between 1 to N+1. I was trying to use this understanding with this tree problem, but then in this case N will keep on changing dynamically as one proceed towards leaf nodes.
Approach 2 : Another thought was to create an array with N+1 empty values and then try to fill them as we go along from root node. But then challenge I faced was on to keep track of first non filled value in this array.
public class TestClass {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter wr = new PrintWriter(System.out);
int T = Integer.parseInt(br.readLine().trim());
for(int t_i = 0; t_i < T; t_i++)
{
int N = Integer.parseInt(br.readLine().trim());
String[] arr_val = br.readLine().split(" ");
int[] val = new int[N];
for(int i_val = 0; i_val < arr_val.length; i_val++)
{
val[i_val] = Integer.parseInt(arr_val[i_val]);
}
String[] arr_parent = br.readLine().split(" ");
int[] parent = new int[N-1];
for(int i_parent = 0; i_parent < arr_parent.length; i_parent++)
{
parent[i_parent] = Integer.parseInt(arr_parent[i_parent]);
}
int[] out_ = solve(N, val, parent);
System.out.print(out_[0]);
for(int i_out_ = 1; i_out_ < out_.length; i_out_++)
{
System.out.print(" " + out_[i_out_]);
}
System.out.println();
}
wr.close();
br.close();
}
static int[] solve(int N, int[] val, int[] parent){
// Write your code here
int[] result = new int[val.length];
ArrayList<ArrayList<Integer>> temp = new ArrayList<>();
ArrayList<Integer> curr = new ArrayList<>();
if(val[0]==1)
curr.add(2);
else{
curr.add(1);
curr.add(val[0]);
}
result[0]=curr.get(0);
temp.add(new ArrayList<>(curr));
for(int i=1;i<val.length;i++){
int parentIndex = parent[i-1]-1;
curr = new ArrayList<>(temp.get(parentIndex));
int nodeValue = val[i];
boolean enter = false;
while(curr.size()>0 && nodeValue == curr.get(0)){
curr.remove(0);
nodeValue++;
enter=true;
}
if(curr.isEmpty())
curr.add(nodeValue);
else if(!curr.isEmpty() && curr.contains(nodeValue) ==false && (enter|| curr.get(0)<nodeValue))
curr.add(nodeValue);
Collections.sort(curr);
temp.add(new ArrayList<>(curr));
result[i]=curr.get(0);
}
return result;
}
}
This can be done in time O(n log n) using augmented BSTs.
Imagine you have a data structure that supports the following operations:
insert(x), which adds a copy of the number x.
remove(x), which removes a copy of the number x.
mex(), which returns the MEX of the collection.
With something like this available, you can easily solve the problem by doing a recursive tree walk, inserting items when you start visiting a node and removing those items when you leave a node. That will make n calls to each of these functions, so the goal will be to minimize their costs.
We can do this using augmented BSTs. For now, imagine that all the numbers in the original tree are distinct; we’ll address the case when there are duplicates later. Start off with Your BST of Choice and augment it by having each node store the number of nodes in its left subtree. This can be done without changing the asymptotic cost of an insertion or deletion (if you haven’t seen this before, check out the order statistic tree data structure). You can then find the MEX as follows. Starting at the root, look at its value and the number of nodes in its left subtree. One of the following will happen:
The node’s value k is exactly one plus the number of nodes in the left subtree. That means that all the values 1, 2, 3, …, k are in the tree, so the MEX will be the smallest value missing from the right subtree. Recursively find the MEX of the right subtree. As you do, remember that you’ve already seen the values from 1 to k by subtracting k off of all the values you find there as you encounter them.
The node’s value k is at least two more than the number of nodes in the left subtree. That means that the there’s a gap somewhere in the node’s in the left subtree plus the root. Recursively find the MEX of the left subtree.
Once you step off the tree, you can look at the last node where you went right and add one to it to get the MEX. (If you never went right, the MEX is 1).
This is a top-down pass on a balanced tree that does O(1) work per node, so it takes a total of O(log n) work.
The only complication is what happens if a value in the original tree (not the augmented BST) is duplicated on a path. But that’s easy to fix: just add a count field to each BST node tracking how many times it’s there, incrementing it when an insert happens and decrementing it when a remove happens. Then, only remove the node from the BST in the case where the frequency drops to zero.
Overall, each operation on such a tree takes time O(log n), so this gives an O(n log n)-time algorithm for your original problem.
public class PathMex {
static void dfs(int node, int mexVal, int[] res, int[] values, ArrayList<ArrayList<Integer>> adj, HashMap<Integer, Integer> map) {
if (!map.containsKey(values[node])) {
map.put(values[node], 1);
}
else {
map.put(values[node], map.get(values[node]) + 1);
}
while(map.containsKey(mexVal)) mexVal++;
res[node] = mexVal;
ArrayList<Integer> children = adj.get(node);
for (Integer child : children) {
dfs(child, mexVal, res, values, adj, map);
}
if (map.containsKey(values[node])) {
if (map.get(values[node]) == 1) {
map.remove(values[node]);
}
else {
map.put(values[node], map.get(values[node]) - 1);
}
}
}
static int[] findPathMex(int nodes, int[] values, int[] parent) {
ArrayList<ArrayList<Integer>> adj = new ArrayList<>(nodes);
HashMap<Integer, Integer> map = new HashMap<>();
int[] res = new int[nodes];
for (int i = 0; i < nodes; i++) {
adj.add(new ArrayList<Integer>());
}
for (int i = 0; i < nodes - 1; i++) {
adj.get(parent[i] - 1).add(i + 1);
}
dfs(0, 1, res, values, adj, map);
return res;
}
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
int nodes = sc.nextInt();
int[] values = new int[nodes];
int[] parent = new int[nodes - 1];
for (int i = 0; i < nodes; i++) {
values[i] = sc.nextInt();
}
for (int i = 0; i < nodes - 1; i++) {
parent[i] = sc.nextInt();
}
int[] res = findPathMex(nodes, values, parent);
for (int i = 0; i < nodes; i++) {
System.out.print(res[i] + " ");
}
}
}

References to nodes in Java linked list

I need some help understanding how a method works.
I have a basic Node class defined like this:
class Node {
Node next = null;
int data;
public Node(int d){
data = d;
}
}
Now I'm looking at how this deleteDuplicates method is working. I understand that we are passing through each node iteratively and storing its value in a set. If the value is already in the set, I believe we are setting the previous node's next pointer to skip the current node. Here's the method:
public static Node deleteDuplicates(Node head){
Node n = head;
HashSet<Integer> set = new HashSet<Integer>();
Node previous = null;
while(n != null) {
if (set.contains(n.data)){
// skip this node
previous.next = n.next;
}
else {
set.add(n.data);
previous = n;
}
n = n.next;
}
return head;
}
I'm confused about the variables previous and n. When we set previous = n;, isn't that making them reference the same object? If they reference the same object, one change you make to n will be the same in previous. So how does the line previous.next = n.next; work?
Thanks!
read these 2 lines together,
previous = n;
n = n.next;
So, once a node is processed, the pointers for previous and n are moved forward. n is next node after previous, thus previous is set to n, and n is moved to its next node, which is n.next
For the deletion part, hope the diagram below helps

BFS not returning a path

I am trying to implement BFS on a 2d array given the start point and end point. I tried giving my function two points on the grid, but it returns an empty array meaning that there is no path.
Can someone please point where am I going wrong and if possible help me correct my error? Thanks.
public Point[] bfs2(Point start, Point end) {
boolean[][] visited = new boolean[50][50];
for (int i = 0; i < visited.length; i++)
for(int j = 0; j < visited.length; j++)
visited[i][j] = false;
visited[start.getX()][start.getY()] = true;
LinkedList<Point> path = new LinkedList<>();
Queue<Point> q = new LinkedList<>();
q.add(start);
while (!q.isEmpty()) {
Point next = q.remove(); //i think the error is here
Point[] neighbours = next.getNeighbours();
path.add(next);
if (next.getX() == end.getX() && next.getY() == end.getY())
break;
else if (!visited[next.getX()][next.getY()]) {
for (Point neighbour : neighbours) {
if (!visited[neighbour.getX()][neighbour.getY()]) {
q.add(neighbour);
}
visited[neighbour.getX()][neighbour.getY()] = true;
}
}
}
Point current = path.removeLast();
ArrayList<Point> v = new ArrayList<>();
while (current.getX() != start.getX() || current.getY() != start.getY()) {
v.add(current);
current = path.removeLast();
}
return v.toArray(new Point[v.size()]);
}
EDIT:
Point current=q.peek();
ArrayList<Point> v=new ArrayList<>();
if(start.getX()==end.getX() && start.getY()==end.getY()) return new Point[0];
while(current.getX()!=start.getX() || current.getY()!=start.getY()){
v.add(current);
current=current.parent;
}
return v.toArray(new Point[v.size()]);
The first issue is that you're adding all the elements you remove from the queue to the path (I'm referring to the line containing path.add(next);).
Instead, you should keep track of the parent node from which you visited each node. When you find the end node, you can trace back your steps to the start node.
If you have exhausted all the nodes and you still haven't found the end node, you can then return an empty list.
Let me know if you need an MCV example, and I'll add it.
Later Edit:
You need to add a Point parent field to your class, like this:
class Point {
int x;
int y;
Point parent; // reference to the Point from which this Point was visited
// constructors, getters, setters, etc.
}
Then you can change your BFS implementation to also set the parent for the current node when iterating through its neighbors. You must change the loop to something like this:
for (Point neighbour : neighbours) {
if (!visited[neighbour.getX()][neighbour.getY()]) {
q.add(neighbour);
visited[neighbour.getX()][neighbour.getY()] = true;
neighbour.parent = next;
}
}

Changing a variable changes the previously assigned variable as well

I'm having what I'm sure is a basic logic error but I can't seem to fix it. I'm sorting a GenericSimpleArrayList before creating a tree using both the unsorted (postorder) and sorted (inorder) lists. When I sort one of the lists it sorts them both? I'm not sure why.
public static <AnyType extends Comparable<? super AnyType>> BinaryNode<AnyType>constructBST ( GenericSimpleArrayList<AnyType> postorder ){
GenericSimpleArrayList <AnyType> g = postorder;
quicksort(postorder, new SortFunctor()); //this is where i sort the list.
GenericSimpleArrayList <AnyType> inorder = postorder;
return constructTree(inorder, g);
}
Can anyone help me fix this? Why does it sort both g and postorder when I only sort postorder? Thanks.
Edit: Added constructTree.
public static <AnyType> BinaryNode<AnyType> constructTree(GenericSimpleArrayList<AnyType> inorder, GenericSimpleArrayList<AnyType> postorder) {
int nodes = postorder.size();
AnyType root = postorder.get(nodes-1);
BinaryNode<AnyType> left = null;
BinaryNode<AnyType> right = null;
if (nodes > 1) {
int rootPos = 0;
for (int loop = 0; loop <= nodes-1; loop++) {
if (inorder.get(loop).equals(root)) {
rootPos = loop;
//System.out.println(loop);
} else {
//System.out.println("Not found at pos: " + loop);
}
}
if (rootPos != 0) {
GenericSimpleArrayList <AnyType> leftInorder = new GenericSimpleArrayList();//(AnyType) new Object[rootPos];
GenericSimpleArrayList <AnyType> leftPostorder = new GenericSimpleArrayList();//(AnyType[]) new Object[rootPos];
for (int loop = 0; loop < rootPos; loop++) {
leftInorder.add(inorder.get(loop));
leftPostorder.add(postorder.get(loop));
}
left = constructTree(leftInorder, leftPostorder );
}
if (rootPos < nodes-1){
GenericSimpleArrayList <AnyType> rightInorder = new GenericSimpleArrayList();//(AnyType[]) new Object[nodes - rootPos - 1];
GenericSimpleArrayList <AnyType> rightPostorder = new GenericSimpleArrayList();//(AnyType[]) new Object[rightInorder.length];
for (int loop = 0; loop < nodes-rootPos-1; loop++){
rightInorder.add(inorder.get(rootPos + loop + 1));
rightPostorder.add(postorder.get(rootPos + loop));
}
right = constructTree(rightInorder, rightPostorder);
}
}
return new BinaryNode<AnyType>(root, left, right);
}
Why does it sort both g and postorder when I only sort postorder?
GenericSimpleArrayList <AnyType> g = postorder;
postorder is a reference to an object. When you copy this reference you now have two references to an object. However there is still only one object.
I don't know the API to your custom ArrayList but I assume you can do
GenericSimpleArrayList<AnyType> g = new GenericSimpleArrayList<AnyType>(postorder);
or
GenericSimpleArrayList<AnyType> g = new GenericSimpleArrayList<AnyType>();
for(AnyType at: postorder)
g.add(at);
Most likely your sorting utility sorts the collection in place. This is very common for sort functions to alter the original list.
If you want to preserve both the original order and sort the list, I suggest first taking a copy of the list.
An alternetive is to use a different structures like a TreeMap to record the String in sorted order and the index of the original position.
GenericSimpleArrayList <AnyType> g = postorder;
GenericSimpleArrayList <AnyType> inorder = postorder;
In these two statements, all the three variable will be referring to the same reference hold by postorder initially. Because you are doing reference assignment and update in one object state will reflect into all the reference variable.
constructTree(inorder, g);
So when you make the above call then you are passing the same same reference.
In this line:
GenericSimpleArrayList <AnyType> g = postorder;
you only define a new name g for the same object. If you want g to be a different List, you need to create it newly (that is really call the constructor) and copy postorder's contents into it.

Understanding linked lists (Java)

can someone please tell me if I am correct? I am studying for a midterm.
x is a variable pointing to a linked-list node and not the last node on the
list. t points to a new node that is not in the list.
x.next = t;
t.next = x.next;
I believe when it comes time to update t.next, x.next is no longer the original node following x, but is instead t itself. So it create a cycle in the list
t = x.next
x = t;
I believe this does nothing to the list.
Thank you in advance!!
You can also do it threadsafe like this:
t.next = x.next; // let t and x point to the SAME next.
x.next = t; // change the x.next to t(who has the old next)
In this case store node in temp variable. It won't create the cycle.
Object temp = x.next;
x.next = t;
t.next = temp;
First you have list like this..
X--->Y----->Z-->
You want to insert a node t after X
Right now t is
t---->null
Step 1- Now we have temp pointing to X's next
x---->y----->z----->
^
|
temp--
Step 2- Now x's next is pointing to t
x----->t---->
now main list is like this
temp---->y---->z---->
Step 3- Now t's next is pointing to temp which is only next pointer
temp---->y--->z---->
^
|
----------
|
x---->t---
So resulting list is
x--->t---->y---->z----->
You already have object x. This probably the current last element of the linked list. Now, you create a new object T and link it as the element after X
X // Lets assume X.next == NULL. So linked list looks like this X -> Null
X.next = T // Now X.next == T and T.Next == NULL, So linked list looks like this X -> T -> Null.
T.next = X.next // Now T.next == T. So linked list is X -> T <->T
This way, when you reach the end of the linked list, it will always return the last element instead of returning NULL.
If you are writing a simple algorithm for this, first you have to create an element and then point its next variable to it self.<First_element>.next = <First_element>. So the logic will work for all the instances.
Here is a simple experiment.
class Node{
Node next = null;
int id =-1;
}
public class LinkedList{
public static void main (String args[]){
Node x = new Node();
x.id = 0;
x.next = x;
// Now add a new element
Node t = new Node();
t.id =1;
x.next = t;
t.next = x.next; // Now we have a linked list of 2 elements
Node mynode = x;//First element of linked list
for(int i =0; i < 3; i++){
System.out.println(mynode.id);
mynode = mynode.next;
}
}
}
Output:
0
1
1

Categories

Resources