I have the code to find the kth from the last element in a list in golang. I wrote a recursive function. When it reaches the end of the list, it will return the count as 1 and increments in further returns. When the count == k then return the node value. But I am getting 'nil pointer dereference' error. Could anyone help me in this?
package main
import (
"container/list"
"fmt"
)
var sMap map[int]bool
func main() {
l := list.New()
for i := 1; i < 100; i++ {
l.PushBack(i)
}
kFromLastElemRec := findKFromLastRecr(l.Front(), 3, WrapObj{0})
fmt.Println(kFromLastElemRec.Value.(int))
}
//Object to store the count
type WrapObj struct {
count int
}
//ERROR
//recursive function to find the kth from last element
func findKFromLastRecr(head *list.Element, k int, wrapper WrapObj) *list.Element {
if head == nil {
return nil
}
resNode := findKFromLastRecr(head.Next(), k, wrapper)
wrapper.count = (wrapper.count) + 1
if wrapper.count == k {
return head
}
return resNode
}
You need to pass a pointer to WrapObj to the findKFromLastRecr() function.
Similar to the languages in the C family, everything in Go is passed by value. That is, a function always gets a copy of the thing being passed, as if there were an assignment statement assigning the value to the parameter.
For instance, passing a WrapObj value to a function makes a copy of the WrapObj, but not the WrapObj it points to.
Therefore, without a pointer to WrapObj, each findKFromLastRecr() function gets a copy of WrapObj and the increase can not be shared by the outer findKFromLastRecr() functions.
It could be useful to check the pointers section from golang-book.
package main
import (
"container/list"
"fmt"
)
var sMap map[int]bool
func main() {
l := list.New()
for i := 1; i < 100; i++ {
l.PushBack(i)
}
kFromLastElemRec := findKFromLastRecr(l.Front(), 3, &WrapObj{0})
fmt.Println(kFromLastElemRec.Value.(int))
}
//Object to store the count
type WrapObj struct {
count int
}
//ERROR
//recursive function to find the kth from last element
func findKFromLastRecr(head *list.Element, k int, wrapper *WrapObj) *list.Element {
if head == nil {
return nil
}
resNode := findKFromLastRecr(head.Next(), k, wrapper)
wrapper.count = (wrapper.count) + 1
if wrapper.count == k {
return head
}
return resNode
}
Output
97
Related
Given a map that uses a struct as its key, where the values of the struct are pointers to another struct:
type Dog struct {
Name string
}
type Cat struct {
Name string
}
type MapKey struct {
dog *Dog
cat *Cat
}
myMap := make(map[MapKey]int)
How would I use the cmp package to make the below maps equal, where they are considered equal because the MapKey has the same values (reflect.DeepEquals or cmp.Equals)?
keyOne := MapKey{
&Dog{Name: "bob"},
&Cat{Name: "clive"},
}
keyTwo := MapKey{
&Dog{Name: "bob"},
&Cat{Name: "clive"},
}
got := map[MapKey]int{
keyOne: 1,
}
want := map[MapKey]int{
keyTwo: 1,
}
In the cmp documentation, it says I could use cmpopts.SortMaps (https://pkg.go.dev/github.com/google/go-cmp/cmp#Equal), however I don't see how this is relevant to my scenario.
I've tried defining a custom Equals function on the MapKey struct but it never gets called.
Go playground to reproduce this:
https://go.dev/play/p/qMxaya3S26M
The cmp.Equal is called with parameters of type map[MapKey]int, not MapKey
So the custom Equal function has to be defined on the type map[MapKey]int.
But to define this function, we need to define a new type from map[MapKey]int.
Here's a playground to the full working example: https://go.dev/play/p/deteHANWQ_3
type MapKeyInt map[MapKey]int
func (m MapKeyInt) Equal(other MapKeyInt) bool {
if len(m) != len(other) {
return false
}
keys, keysOther := make([]MapKey, 0), make([]MapKey, 0)
values, valuesOther := make([]int, 0), make([]int, 0)
for k, v := range m {
keys = append(keys, k)
values = append(values, v)
}
for k, v := range other {
keysOther = append(keysOther, k)
valuesOther = append(valuesOther, v)
}
for i := 0; i < len(m); i++ {
if (keys[i].dog.Name != keysOther[i].dog.Name) || (keys[i].cat.Name != keysOther[i].cat.Name) {
return false
}
if values[i] != valuesOther[i] {
return false
}
}
return true
}
This function
List<int> _calculateTrips() {
List<int> trips = [];
trips = List.generate(
30,
(index) {
var counter = 0;
var aDay = DateTime.now().subtract(Duration(days: index));
for (var aWalk in walks) {
if ((aDay.month == aWalk.month) && (aDay.day == aWalk.day)) {
counter++;
}
}
trips.add(counter);
},
);
return trips;
}
creates the error The body might complete normally, causing null to be returned, but the return type is a potentially non-nullable type.Try adding either a return or a throw statement at the end. I'm struggling a bit to understand the message because (a) I thought I initialized the list at the beginning of the function and (b) I thought I had a return statement at the end.
The issue is with the function you pass to List.generate(). It expects a E Function(int), where E is the type of the element, for example:
final evenNumbers = List.generate(10, (index) {
return index * 2;
});
Your issue comes from trips.add(counter):
List<int> trips = [];
trips = List.generate(30, (index) {
final trip = calculateTrip(index);
trips.add(trip);
})
The inner function needs to be an int Function(int) (i.e. a function that takes an int, and returns an int), because your list is a List<int>.
However, your inner function never returns anything.
Simply replace trips.add(counter); with return counter; and it should solve this error. You may also want to refactor your function a little:
List<int> _calculateTrips() => List.generate(30, (index {
var counter = 0;
var aDay = DateTime.now().subtract(Duration(days: index));
for (var aWalk in walks) {
if ((aDay.month == aWalk.month) && (aDay.day == aWalk.day)) {
counter++;
}
}
return counter;
});
I came across this leetcode problem Insert Delete GetRandom where it is asked to implement a Data Structure to support Insert, Delete and getRandom in average O(1) time, and solved it as using map and a vector.
My solution passes all the test cases except for the last one and I'm not able to figure out why? The last test case is really very large to debug.
I changed my code a little bit and then it passes but still didn't got why the previous one didn't pass.
Non-Accepted Solution:
class RandomizedSet {
map<int, int> mp;
vector<int> v;
public:
/** Initialize your data structure here. */
RandomizedSet() {
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
bool insert(int val) {
if(mp.find(val) == mp.end()){
v.push_back(val);
mp[val] = v.size()-1;
return true;
}
else return false;
}
/** Removes a value from the set. Returns true if the set contained the specified element. */
bool remove(int val) {
if(mp.find(val) == mp.end()){
return false;
}
else{
int idx = mp[val];
mp.erase(val);
swap(v[idx], v[v.size()-1]);
v.pop_back();
if(mp.size()!=0) mp[v[idx]] = idx;
return true;
}
}
/** Get a random element from the set. */
int getRandom() {
if(v.size() == 0) return 0;
int rndm = rand()%v.size();
return v[rndm];
}
};
/**
* Your RandomizedSet object will be instantiated and called as such:
* RandomizedSet* obj = new RandomizedSet();
* bool param_1 = obj->insert(val);
* bool param_2 = obj->remove(val);
* int param_3 = obj->getRandom();
*/
Accpeted Solution:
The problem is in remove function, when i change the remove function by below code, it passes.
if(mp.find(val) == mp.end()){
return false;
}
else{
int idx = mp[val];
swap(v[idx], v[v.size()-1]);
v.pop_back();
mp[v[idx]] = idx;
mp.erase(val);
return true;
}
I don't understand why is this happening. I placed the mp.erase(val) in the last and replaced the if(mp.size()!=0) mp[v[idx]] = idx to mp[v[idx]] = idx only.
Both versions of remove function are able to handle corner case - when there is only single element left in the map and we want to remove it.
LeetCode 380
This is because of undefined behavior when the element removed is the last element.
e.g, say the operations are
insert(1) // v = [1], mp = [1->0]
insert(2) // v = [1,2], mp = [1->0, 2->1]
remove(2):
int idx = mp[val]; // val = 2, idx = 1
mp.erase(val); // mp = [1->0]
swap(v[idx], v[v.size()-1]); // idx = v.size()-1 = 1, so this does nothing.
v.pop_back(); // v = [1]
if(mp.size()!=0) mp[v[idx]] = idx; // mp[v[1]] = 1.
// But v[1] is undefined after pop_back(), since v's size is 1 at this point.
I am guessing that it doesn't clear the memory location accessed by v[1], so v[1] still points to 2, and it ends up putting 2 back into mp.
In my use case, I would like to know how the following Java code would be implemented in Go
class TreeNode {
public int data;
public TreeNode left;
public TreeNode right;
public TreeNode(){}
}
LinkedList<TreeNode> treeList = new LinkedList<TreeNode>();
I am able to import the container/list package and add an interface. But it is not allowing any generic object. Do I have to implement my own version of list with TreeNode struct?
I just need to know how LinkedList<T> would work in Go.
EDIT 1: To make it clear, I am adding the complete code here. I am trying to find the linked list of all nodes at each depth in a binary tree. I used two packages list and binary tree. You can find the source code for binarytree here and list here. list is same as container/list but I added few extra functions
package main
import (
"fmt"
"go/chapter02-linkedlists/list"
"go/chapter04-treesandgraphs/binarytree"
)
func main() {
inArr := []int{4, 5, 7, 8, 9}
t1 := binarytree.NewMinimalHeightBST(inArr, 0, len(inArr)-1)
binarytree.InOrderTraverse(t1)
var nodeList []*list.List
nodeList = getLevelbasedList(t1, 0)
fmt.Println()
for _, value := range nodeList {
fmt.Print("[ ")
for x := value.Front(); x != nil; x = x.Next() {
fmt.Print(x.Value.(int), " ")
}
fmt.Println("]")
}
}
func getLevelbasedList(root *binarytree.Tree, level int) []*list.List {
if root == nil {
return nil
}
var nodeList []*list.List
parents := list.New()
current := list.New()
current.PushFront(root)
for current.Len() > 0 {
nodeList = append(nodeList, current)
parents = current
current = list.New()
for x := current.Front(); x != nil; x = x.Next() {
node := x.Value.(*binarytree.Tree)
if node.Left != nil {
current = current.PushFront(node.Left)
}
if node.Right != nil {
current = current.PushFront(node.Right)
}
}
return nodeList
}
}
And the error is,
./question4_4b.go:56: cannot use current.PushFront((interface {})(node.Left)) (type *list.Element) as type *list.List in assignment
./question4_4b.go:59: cannot use current.PushFront((interface {})(node.Right)) (type *list.Element) as type *list.List in assignment
EDIT 2: Based on JamesHenstridge's comment I edited from
current = current.PushFront(node.Left)
to
current.PushFront(node.Left)
And the issue resolved. But now I am getting interface conversion error,
[ panic: interface conversion: interface is *binarytree.Tree, not int
goroutine 1 [running]:
Go doesn't support generic types (see FAQ question Why does Go not have generic types?).
You have to use Type assertions to obtain the typed value you want.
E.g. create your TreeNode type:
type TreeNode struct {
Data int
Left *TreeNode
Right *TreeNode
}
And to iterate over a list containing TreeNode values:
l := list.New()
// Populate list
for e := l.Front(); e != nil; e = e.Next() {
if tn, ok := e.Value.(TreeNode); ok {
// do something with tn which is of type TreeNode
fmt.Println(tn)
} else {
// e.Value is not of type TreeNode
}
}
If you assemble the list and you can be sure it only contains values of type TreeNode, you can omit the error check in the type assertion and it becomes like this:
for e := l.Front(); e != nil; e = e.Next() {
// if e.Value would not be of type TreeNode, run-time panic would occur
tn := e.Value.(TreeNode) // tn is of type TreeNode
fmt.Println(tn)
}
Edit:
The error you're getting:
cannot use current.PushFront((interface {})(node.Left)) (type *list.Element)
as type *list.List in assignment
At line:
current = current.PushFront(node.Left)
The current variable is of type list.List, and the method current.PushFront() returns a value of type *list.Element. These are 2 different types, you can't assign a *Element to a variable that has a type of List.
Edit 2:
Your 2nd error:
panic: interface conversion: interface is *binarytree.Tree, not int
Is caused by the line:
fmt.Print(x.Value.(int), " ")
You try to assert that the value x.Value is of type int but it isn't! x.Value is of type *binarytree.Tree so the assertion will obviously fail.
I've written the following code but it doesn't give the correct result (for instance if you enter [-1,-1], it returns [-1,-1,-1].
import std.stdio, std.range, std.container, std.algorithm;
DList!T strandSort(T)(DList!T list) {
static DList!T merge(DList!T left, DList!T right) {
DList!T res;
while (!left.empty && !right.empty) {
if (left.front <= right.front) {
res.insertBack(left.front);
left.removeFront();
} else {
res.insertBack(right.front);
right.removeFront();
}
}
res.insertBack(left[]);
res.insertBack(right[]);
return res;
}
DList!T result, sorted;
while (!list.empty) {
sorted.clear();
sorted.insertBack(list.front);
list.removeFront();
foreach (item; list) {
if (sorted.back <= item) {
sorted.insertBack(item);
list.stableLinearRemove(list[].find(item).take(1)));
}
}
result = merge(sorted, result);
}
return result;
}
void main() {
auto lst = DList!int([-1,-1]);
foreach (e; strandSort(lst))
writef("%d ", e);
}
Sometimes, the stableLinearRemove doesn't remove the item from the list. The question is, is it a bug in my code, or in Phobos?
See also the discusion on Rosettacode.org
Edit: I suspect it's caused by removeFront. It doesn't set the prev node pointer of the second node to null when the first node is removed. When the item to be removed from the list by linearRemove happens to be the first node, it won't be removed. The remove function checks "before" and "after" nodes and the "before" is still set. If I write it like this, it does work:
if (sorted.back <= item) {
sorted.insertBack(item);
if (list.front == item)
list.removeFront();
else
list.stableLinearRemove(list[].find(item).take(1)));
}
I don't think it's a bug in Phobos, but rather a gotcha. You shouldn't rely on linearRemove to remove an element if it might be the first in the list. Check for that first and use removeFront. Is also more efficient.
In the case above, a better solution would be to copy the list:
DList!T result, sorted, leftover;
while (!list.empty) {
leftover.clear();
sorted.clear();
sorted.insertBack(list.front);
list.removeFront();
foreach (item; list) {
if (sorted.back <= item)
sorted.insertBack(item);
else
leftover.insertBack(item);
}
result = merge(sorted, result);
list = leftover;
}
You are right, it is definitely a bug in removeFront.
Though I might point out that removing iterated elements via foreach is not going to be efficient even if it is supposed to be valid. you need a handle to the range. consider:
auto rng = list[];
while(!rng.empty) {
auto item = rng.front;
if(sorted.back <= item) {
sorted.insertBack(item);
auto rng2 = rng.save();
rng.popFront();
list.stableLinearRemove(rng2.take(1)); // O(1) removal!
}else{
rng.popFront();
}
}
Ah, well. Above probably doesn't work in light of the bug.