https://leetcode.com/problems/last-stone-weight/
We have a collection of rocks, each rock has a positive integer weight.
Each turn, we choose the two heaviest rocks and smash them together. Suppose the stones have weights x and y with x <= y. The result of this smash is:
If x == y, both stones are totally destroyed; If x != y, the stone of weight x is totally destroyed, and the stone of weight y has new weight y-x. At the end, there is at most 1 stone left. Return the weight of this stone (or 0 if there are no stones left.)
Example 1:
Input: [2,7,4,1,8,1] Output: 1 Explanation: We combine 7 and 8 to get 1 so the array converts to [2,4,1,1,1] then, we combine 2 and 4 to get 2 so the array converts to [2,1,1,1] then, we combine 2 and 1 to get 1 so the array converts to [1,1,1] then, we combine 1 and 1 to get 0 so the array converts to [1] then that's the value of last stone.
Please review performance.
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Heap
{
/// <summary>
/// https://leetcode.com/problems/last-stone-weight/
/// </summary>
[TestClass]
public class LastStoneWeightMaxHeap
{
[TestMethod]
public void MaxHeapTest()
{
BinaryMaxHeap h = new BinaryMaxHeap(6);
h.InsertKey(2);
h.InsertKey(7);
h.InsertKey(4);
h.InsertKey(1);
h.InsertKey(8);
h.InsertKey(1);
Assert.AreEqual(8, h.ExtractMax());
Assert.AreEqual(7, h.ExtractMax());
Assert.AreEqual(4, h.ExtractMax());
Assert.AreEqual(2, h.ExtractMax());
Assert.AreEqual(1, h.ExtractMax());
Assert.AreEqual(1, h.ExtractMax());
}
[TestMethod]
public void LastStoneWeightTest()
{
int[] input = {2, 7, 4, 1, 8, 1};
Assert.AreEqual(1, LastStoneWeight(input));
}
[TestMethod]
public void LastStoneWeightCaseTest()
{
int[] input = { 2,2};
Assert.AreEqual(0, LastStoneWeight(input));
}
public int LastStoneWeight(int[] stones)
{
BinaryMaxHeap h = new BinaryMaxHeap(stones.Length);
foreach (var stone in stones)
{
h.InsertKey(stone);
}
while (h.Count > 1)
{
var stone1 = h.ExtractMax();
var stone2 = h.ExtractMax();
if (stone1 == stone2)
{
continue;
}
h.InsertKey(stone1 - stone2);
}
return h.ExtractMax();
}
}
public class BinaryMaxHeap
{
private readonly int[] _heapArr;
private readonly int _capacity;
public uint _heapSize;
public BinaryMaxHeap(int capacity)
{
_capacity = capacity;
_heapSize = 0;
_heapArr = new int[capacity];
}
public void InsertKey(int key)
{
if (_heapSize == _capacity)
{
throw new StackOverflowException("overflow can't insert key");
}
//insert the new key at the end
_heapSize++;
uint i = _heapSize - 1;
_heapArr[i] = key;
//fix the heap as max heap
// Fix the max heap property if it is violated
while (i != 0 && _heapArr[Parent(i)] < _heapArr[i]) //bubble is generic specific
{
Swap(i, Parent(i));
i = Parent(i);
}
}
public int ExtractMax()
{
if (_heapSize <= 0)
{
return 0;
}
if (_heapSize == 1)
{
_heapSize--;
return _heapArr[0];
}
// Store the minimum value, and remove it from heap
int root = _heapArr[0];
_heapArr[0] = _heapArr[_heapSize - 1];
_heapSize--;
Heapify(0);
return root;
}
private void Heapify(uint i)
{
uint l = Left(i);
uint r = Right(i);
uint largest = i;
if (l < _heapSize && _heapArr[i]< _heapArr[l])
{
largest = l;
}
if (r < _heapSize && _heapArr[largest] < _heapArr[r])
{
largest = r;
}
if (largest != i)
{
Swap(i, largest);
Heapify(largest);
}
}
private void Swap(uint key1, uint key2)
{
int temp = _heapArr[key2];
_heapArr[key2] = _heapArr[key1];
_heapArr[key1] = temp;
}
private uint Parent(uint i)
{
return (i - 1) / 2;
}
private uint Right(uint i)
{
return 2 * i + 2;
}
private uint Left(uint i)
{
return 2 * i + 1;
}
public int GetMax()
{
return _heapArr[0];
}
public uint Count
{
get { return _heapSize; }
}
}
}