Removing nodes between two given positions from singly linked list? - java

I am teaching myself data structures and following to Java books on this subject. Currently I am learning Linked List implementation. I have been struggling with how to write a method which takes "startPos" and "endPos" and simply removes the nodes accordingly. I am validating "startPos", and "endPos" in order to catch invalid position input. I have Googled for direction but have not come across any online example that can help me get going with this logic. I would highly appreciate any guidance with this please. Thank you.
class Node{
public Object data;
public Node next;
}
Delete Nodes Method
public void deleteNodes( int startPos, int endPos ){
Node node = _nHead;
int counter = 0;
if( startPos < 1 || startPos > getSize() )
return;
if( endPos < 1 || endPos > getSize() )
return;
while( node != null){
node = node.next;
++counter;
}
}
GET SIZE
public int getSize(){
int counter = 0;
for( Node node = _nHead; node != null; node = node.next )
++counter;
return counter;
}

To remove all nodes between two nodes on a singly linked list is not super hard.
You need two placeholders. You move through the linked list until you find your start node, and set one of the placeholders equal to it. You then move your second placeholder through the remainder of the linked list until you find your second node. Set your first node's -> next parameter equal to the second node, and you've effectively removed everything in between.
For proper cleanup, you should keep track of the node that was next after the first node and free all nodes that were removed from memory, but this is more critical in C than Java.
For a doubly-linked list the method is similar, except you also have to set the second node's previous to the first node.
As an example:
public void deleteNodes( int startPos, int endPos ){
Node node = _nHead;
Node start;
Node end;
int counter = 0;
if( startPos < 1 || startPos > getSize() )
return;
if( endPos < 1 || endPos > getSize() )
return;
if (endPos < startPos)
{
int placeholder = startPos;
startPos = endPos;
endPos = placeholder; // switches end and start if start is greater than end
}
if (endPos == startPos)
return; // if they are equal we aren't deleting anything;
while( node != null)
{
if (counter == startPos)
start = node;
if (counter == endPos)
end = node;
node = node.next;
counter++;
}
if (start != NULL && end != NULL)
{
start.next = end;
}
}

You would simply have to set the next pointer of the node at the start of the removal range to the node at the end of the removal range. Since there would be no references to the nodes in the delete range, Java's garbage collection should clear them up.

Related

Finding the 'maximum' character in a linked list Java recursively

I am trying to find the "maximum" value in a linked list recursively using a helper function. I am just starting to learn about these in my class and am pretty confused. We have a custom class that defines the type Node and another function to calculate the size of the Node or linkedlist. I solved this problem when I was comparing integers, but with characters I am lost. Here is my code:
'''
static class Node {
public Node (char item, Node next) { this.item = item; this.next = next; }
public char item;
public Node next;
}
Node first; // this is the only instance variable,
// the access point to the list
// size
//
// a function to compute the size of the list, using a loop
// an empty list has size 0
public int size () {
int count = 0;
for (Node tmp = first; tmp != null; tmp = tmp.next)
count++;
return count;
}
/*
* maxCharacter
*
* a function to compute the 'maximum' character in the list using recursion
* You will want to create a helper function to
* do the recursion
*
* precondition: list is not empty
*
* Examples:
* ["ababcdefb"].maxCharacter() == 'f'
* ["eezzg"].maxCharacter() == 'z'
* ["a"].maxCharacter() == 'a'
*/
public char maxCharacter () {
return maxCharacterHelper(first, first.size());
}
public char maxCharacterHelper(Node first, int index) {
char[] alpha = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
int max = 0;
while(index > 0 )
max = alpha.indexOf(first.item) > max ? first.item : max;
maxCharacterHelper(first, index-1);
return max;
}
'''
If you could explain how I would loop through the list recursively while maintaining the greatest char I would greatly appreciate it.
The golden rule with recursion is "Think of the base case first, then write the recurrence".
In this case, the base is the empty list. In this case, the maximum is the last value you've seen.
The recurrence is just a call to the rest of the list with the highest value you've called.
public static MaxNode(Node n, char currentMax) {
if (n == null) // base case, we're at the end.
return currentMax;
// recurrence
return MaxNode(n.next, currentMax > n.item ? currentMax : n.item);
}
For simple ASCII values, you can treat the maximum using the > operator.
Your while loop is confusing because of indentation and because you never change index. However, I don't think you need it if your intent is to use recursion. Generally with recursion you need to establish a base case from which you cannot recurse. For a linked list the natural base case is where there is no next node, rather than index-based.
if (current.next == null)
return alpha.indexOf(current.item);
Otherwise combine the recursion return with the current value
int remainingMax = maxCharacterHelper(current);
int currentValue = alpha.indexOf(current.item);
return (remainingMax > currentValue) ? remainingMax : currentValue;
Here is how I would put it together
//I made it static because it is not a method of a specific Node
public static int maxCharacterHelper(Node currentNode){
// remaining list includes only current node, so this one has max value
if (current.next == null)
return alpha.indexOf(current.item);
//otherwise take the larger of remaining list and current node
int remainingMax = maxCharacterHelper(current.next);
int currentValue = alpha.indexOf(current.item);
return (remainingMax > currentValue) ? remainingMax : currentValue;
}

Solution timing out for question: build binary tree from inorder and postorder

I've been grinding leetcode recently and am perplexed on why my solution is timing out when I submit it to Leetcode.
Here is the question:
https://leetcode.com/explore/learn/card/data-structure-tree/133/conclusion/942/
Given inorder and postorder traversal of a tree, construct the binary tree.
Note:
You may assume that duplicates do not exist in the tree.
For example, given
inorder = [9,3,15,20,7]
postorder = [9,15,7,20,3]
Return the following binary tree:
3
/ \
9 20
/ \
15 7
Here is my solution that times out in one of the test cases:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (inorder == null || inorder.length == 0) {
return null; // input error
}
if (postorder == null || postorder.length == 0) {
return null; // input error
}
if (postorder.length != inorder.length) {
return null; // input error
}
List<Integer> inOrder = new ArrayList<Integer>();
List<Integer> postOrder = new ArrayList<Integer>();
for (int i = 0; i < inorder.length; i++) {
inOrder.add(inorder[i]);
postOrder.add(postorder[i]);
}
return buildBinaryTree(inOrder, postOrder);
}
public TreeNode buildBinaryTree(List<Integer> inOrder, List<Integer> postOrder) {
boolean found = false;
int root = 0;
int rootIndex = 0;
// for given in-order scan the post-order right to left to find the root
for (int j = postOrder.size() - 1; j >= 0 && !found; j--) {
root = postOrder.get(j);
if (inOrder.contains(root)) {
rootIndex = inOrder.indexOf(root);
root = inOrder.get(rootIndex);
found = true;
break;
}
}
if (found) {
List<Integer> leftOfRoot = new ArrayList<Integer>();
List<Integer> rightOfRoot = new ArrayList<Integer>();
if (rootIndex > 0) {
leftOfRoot.addAll(inOrder.subList(0, rootIndex));
}
if ((rootIndex + 1) < inOrder.size()) {
rightOfRoot.addAll(inOrder.subList(rootIndex + 1, inOrder.size()));
}
TreeNode node = new TreeNode(root);
node.left = buildBinaryTree(leftOfRoot, postOrder);
node.right = buildBinaryTree(rightOfRoot, postOrder);
return node;
}
return null;
}
}
Can anyone help determine why this is happening? I'm thinking it is the Leetcode judge at fault here and my code is fine.
Leetcode's judge is probably OK. This code is too casual about nested linear array operations and heap allocations. Creating ArrayLists and calling contains, addAll, subList and indexOf may appear innocuous, but they should all be thought of as extremely expensive operations when inside a recursive function that spawns two child calls in every frame.
Let's unpack the code a bit:
List<Integer> inOrder = new ArrayList<Integer>();
List<Integer> postOrder = new ArrayList<Integer>();
for (int i = 0; i < inorder.length; i++) {
inOrder.add(inorder[i]);
postOrder.add(postorder[i]);
}
This is a minor up-front cost but it's an omen of things to come. We've done 2 heap allocations that weren't necessary and walked n. I'd stick to primitive arrays here--no need to allocate objects other than the result nodes. A lookup map for inOrder with value -> index pairs might be useful to allocate if you feel compelled to create a supporting data structure here.
Next, we step into buildBinaryTree. Its structure is basically:
function buildBinaryTree(root) {
// do some stuff
if (not base case reached) {
buildBinaryTree(root.left)
buildBinaryTree(root.right)
}
}
This is linear on the number of nodes in the tree, so it's important that // do some stuff is efficient, hopefully constant time. Walking n in this function would give us quadratic complexity.
Next there's
for (int j = postOrder.size() - 1; j >= 0 && !found; j--) {
root = postOrder.get(j);
if (inOrder.contains(root)) {
rootIndex = inOrder.indexOf(root);
This looks bad, but by definition the root is always the last element in a postorder traversal array, so if we keep a pointer to it, we can remove this outer loop. You can use indexOf directly and avoid the contains call since indexOf returns -1 to indicate a failed search.
The code:
if (found) {
List<Integer> leftOfRoot = new ArrayList<Integer>();
List<Integer> rightOfRoot = new ArrayList<Integer>();
does more unnecessary heap allocations for every call frame.
Here,
leftOfRoot.addAll(inOrder.subList(0, rootIndex));
Walks the list twice, once to create the sublist and again to add the entire sublist to the ArrayList. Repeat for the right subtree for two full walks on n per frame. Using start and end indices per call frame means you never need to allocate heap memory or copy anything to prepare the next call. Adjust the indices and pass a reference to the same two arrays along the entire time.
I recommend running your code with a profiler to see exactly how much time is spent copying and scanning your ArrayLists. The correct implementation should do at most one walk through one of the lists per call frame to locate root in inOrder. No array copying should be done at all.
With these modifications, you should be able to pass, although wrangling the pointers for this problem is not obvious. A hint that may help is this: recursively process the right subtree before the left.
Yes, it would be much faster with arrays. Try this:
public static TreeNode buildTree(int[] inorder, int[] postorder, int start,
int end) {
for (int i = postorder.length-1; i >= 0; --i) {
int root = postorder[i];
int index = indexOf(inorder, start, end, root);
if (index >= 0) {
TreeNode left = index == start
? null
: buildTree(inorder, postorder, start, index);
TreeNode right = index+1 == end
? null
: buildTree(inorder, postorder, index+1, end);
return new TreeNode(root, left, right);
}
}
return null;
}
private static int indexOf(int[] array, int start, int end, int value) {
for (int i = start; i < end; ++i) {
if (array[i] == value) {
return i;
}
}
return -1;
}

Deleting a Node from a Linked List

I'm trying to delete a given Node from a Linked List. I don't know why my code is not working. Any hints?
So I have [11,21,31,41] and they are asking me to delete the node at index 2 in this case 31. So far I have this:
public void delete (int k) {
//[ 11 21 31 41 ].delete( 2 ): expected=[ 11 21 41 ]
if (k < 0 || k >= N) throw new IllegalArgumentException ();
for(Node x = first; x != null; x = x.next) {
//deletes node
if(x.item == k){
x = x.next;
}
if(x.item <= k){
x = x.next.next;
}
}
}
Can someone tell me please why is this not working? Thank you
You could move nodes using next k times. Store a temporary int and a previous node. Decrement the temporary int each time you call next(). Once you are at 0 (the desired element), remove by setting the previous node's next pointer to x's next pointer, and then set x to null.
I think in your code you are missing the part where pointers are set.
For example:
(1) -> (2) -> (3)
To remove (2), set (1).next = (3) and (2) = null. This will get:
(1) -> (3)
There are a couple of things going wrong here, and I encourage you to work on some println debugging to better understand the issues as you develop.
Assuming the item field is the value of the Node, you're comparing that value of a Node to the index of said Node (e.g. x.item == k).
The general logic that you're going to want to follow is, "if the Node the iterator is pointing to is the next Node in my list, set my next to its next."
In your code you are comparing the value of node with the index you passed. This comparison will always have index less than value in node. Also after that you are not updating the node when you assume the code is correct.
Below code should give you the result.
public void delete (int k)
{
//[ 11 21 31 41 ].delete( 2 ): expected=[ 11 21 41 ]
if (k < 0 || k >= N) throw new IllegalArgumentException ();
int count = 0;//Assuming index starts from 0
Node prev;
for(Node x = first; x != null; x = x.next)
{
//deletes node
count++;
if(count<k)
{
prev = x;
continue;
}
else
{
prev.next = x.next;
x.next = null;
break;
}
}
if(count>k || count<k)
{
System.out.println("No element with index k");
}
}
#vase is correct saying
Assuming the item field is the value of the Node, you're comparing
that value of a Node to the index of said Node (e.g. x.item == k).
some example code that could fix this
public void delete(int k){
Node n = first;
for(int i = 0; i < k-1; i++){ // this loop finds the node right before the
n=n.next; // index to use to delete the desired index.
}
n.next = n.next.next; // delete command
}

LinkedList function from InterviewBit

I'm struggling with my solution for a question on InterviewBit.
I linked to the full description, but in short:
1) You are given the head node of a linkedlist
2) take the first half of the list and change the values so that:
"1st node’s new value = the last node’s value - first node’s current value
2nd node’s new value = the second last node’s value - 2nd node’s current value"
Here is my approach (it compiles but does not mutate the list at all)
I see that my method does not actually modify the original list -- it seems like what I'm doing is making a new list with the correctly altered values, but not changing the original.
/**
* Definition for singly-linked list.
* class ListNode {
* public int val;
* public ListNode next;
* ListNode(int x) { val = x; next = null; }
* }
*/
public class Solution {
public ListNode subtract(ListNode a) {
ListNode current = a;
int length = 0;
//get length
while(current.next != null){
length++;
current = current.next;
}
length += 1;
while(current.next != null){
double half = Math.floor(length/2);
for(int i=0; i<half; i++ ){
//
// if(i == 0){
// int aval = (nthToLast(a, length)).val - a.val;
// a.val = ((nthToLast(a, length-i)).val - a.val);
// a.next = current;
// }
current.val = ((nthToLast(a, length-i)).val - current.val);
current = current.next;
}
}
return a;
}
/* Helper function that given LinkedList head, and int n,
returns the nth to last ListNode in the LinkedList */
public ListNode nthToLast(ListNode head, int n){
ListNode nth = head;
ListNode ahead = head;
/* strategy: set nth to head, and 'ahead' to n places in front of 'nth'
increment at same speed and then when 'ahead' reaches the end, 'nth'
will be in the nth place from the end.
*/
while(ahead.next != null){
for(int i=0; i<n; i++){
ahead = ahead.next;
}
nth = nth.next;
ahead = ahead.next;
}
return nth;
}
}
Also -- I'm trying to get better at questions like these. Is this an ok approach for this question? I'd like to figure out how to make this work, but also if this is an all around bad approach please let me know.
break code into simple helper functions,
make a function to get value of nth element in the linked list(this function is very easy to write)
,and then traverse the list upto the half every time calling that function to get the value of listSize-i member of the list and edit the value of the the ith member of the list. and make changes to the 1st few elements manually to check weather your linkList implementation is working or not
/**
* Definition for singly-linked list.
**/
class ListNode {
public int val;
public ListNode next;
ListNode(int x) { val = x; next = null; }
}
public class Solution {
public ListNode subtract(ListNode a) {
ListNode current = a;
int length = 0;
//get length
while(current.next != null){
length++;
current = current.next;
}
length += 1;
int half = length/2;
//logic of this loop is
//go from 0 to half of the list
// j goes from the last element to half
//for example if size of list is 6 (indexing from 0)
//when i is 0 j is 5
//when i is 1 j is 4 and so on
//so you get what you wanted
for(int i=0,j=length-1; i<half; i++,j-- ){
current.val=nthElement(a,j).val-current.val;
current = current.next;
}
return a;
}
/* Helper function that given LinkedList head, and int n,
returns the nth node of LinkedList */
public ListNode nthElement(ListNode head, int n){ //e.g-if n is 5 it will return the 5th node
ListNode nth = head;
for(int i=0; i<n; i++){
nth = nth.next;
}
return nth;
}
}

Find numbers of nodes between root and give node

So in a given binary tree (node binary search tree), initially I want to find the number of nodes between two nodes "p" and "q". I first find the lowest common ancestor between these two nodes, say, "ancestor". Then I calculate the number of nodes between "ancestor" and "p" and number of nodes between "ancestor" and "q" separately and add them at last.
I tried recursive way to get number of nodes between "ancestor" and "p" or "q" but failed. Not a fan of recursive.
public static int NodeToNodePath(BinaryTree root, BinaryTree node, int length){
if(root == null && node == null)
return 0;
if(root == null || node == null)
return 0;
if(root.rootElement == node.rootElement){
return length;
}
int sum = NodeToNodePath(root.left, node, length + 1);
if(sum != 0)
return sum;
sum = NodeToNodePath(root.right, node, sum);
return sum;
}
But in this way, the result from root to left mode is correct but can't find node on the other size.
Any help?
Thanks!
I figure out how to solve the problem. By recursion. This may not apply to my origin problem
"find node number between two given nodes" but it does return number of nodes between root and a given node.
Code is posted below.
public static int NodeToNodePath(BinaryTree root,
BinaryTree node, int length) {
if(root == null)
return 0;
if(root.rootElement == node.rootElement){
length += 1;
return length;
}
int left = NodeToNodePath(root.left, node, length);
if(left != 0){
return left + 1;
}
int right = NodeToNodePath(root.right, node, length);
if(right != 0){
return right + 1;
}
return 0;
}
Also, I found a post on GeekForGeeks talking specifically about my origin problem, it's called "Find distance between two given keys of a Binary Tree" the address is:
http://www.geeksforgeeks.org/find-distance-two-given-nodes/
Thanks everyone!

Categories