问题
Insertion Sort is a simple sorting technique which was covered in previous challenges. Sometimes, arrays may be too large for us to wait around for insertion sort to finish. Is there some other way we can calculate the number of times Insertion Sort shifts each elements when sorting an array?
If ki is the number of elements over which ith element of the array has to shift then total number of shift will be k1 + k2 + … + kN.
Input:
The first line contains the number of test cases T. T test cases follow. The first line for each case contains N, the number of elements to be sorted. The next line contains N integers a[1],a[2]…,a[N].
Output:
Output T lines, containing the required answer for each test case.
Constraints:
1 <= T <= 5
1 <= N <= 100000
1 <= a[i] <= 1000000
Sample Input:
2
5
1 1 1 2 2
5
2 1 3 1 2
Sample Output:
0
4
Explanation
First test case is already sorted therefore there’s no need to shift any element. In second case it will proceed in following way.
Array: 2 1 3 1 2 -> 1 2 3 1 2 -> 1 1 2 3 2 -> 1 1 2 2 3
Moves: - 1 - 2 - 1 = 4
思路:
1.使用AVL tree减少遍历时间,构造可以重复键的RBTree, 然后构造OSTree。
using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Collections.Generic;
//https://www.hackerrank.com/challenges/insertion-sort
namespace Sort_Insertion_Sort_Advanced_Analysis
{
class Program
{
static void Main(string[] args)
{
using (System.IO.TextReader streamReader =
new StreamReader("input04.txt"))
{
int T = int.Parse(streamReader.ReadLine());
for (int i = 0; i < T; i++)
{
int N = int.Parse(streamReader.ReadLine());
String[] stringValues = streamReader.ReadLine().Split(' ');
int[] intValues = Array.ConvertAll(stringValues, int.Parse);
Console.WriteLine(CountStepsOSTree(intValues));
}
Console.ReadKey();
}
}
private static long CountStepsOSTree(int[] intValues)
{
Dictionary<int, int> map = new Dictionary<int, int>();
RedBlackTree<RedBlackTreeNode<DuplicatableKey>, DuplicatableKey> rbTree = new RedBlackTree<RedBlackTreeNode<DuplicatableKey>,DuplicatableKey>();
long result = 0;
for(int i = 0; i < intValues.Length; i++)
{
DuplicatableKey key = new DuplicatableKey();
key.Count = i;
key.Size = 1;
key.Key = intValues[i];
var node = rbTree.InsertNode(key);
result += (i + 1 - rbTree.OSRank(node))
}
return result;
}
public enum NodeColor
{
Black,
Red
}
public class DuplicatableKey : IComparable<DuplicatableKey>
{
int key = -1;
public int Key
{
get { return key; }
set { key = value; }
}
int count = 0;
public int Count
{
get { return count; }
set { count = value; }
}
int size = 0;
public int Size
{
get { return size; }
set { size = value; }
}
public int CompareTo(DuplicatableKey obj)
{
int result;
result = this.key - obj.key;
if(result == 0)
return this.count - obj.count;
else
return result;
}
}
/// <summary>
/// A binary search tree is a red-black tree if it satisfies the following red-black properties:
/// 1) Every node is either red or black.
/// 2) The root is black.
/// 3) Every leaf (NIL) is black.
/// 4) If a node is red, then both its children are black.
/// 5) For each node, all paths from the node to descendant leaves contain the same number of black nodes.
///
/// Red-black trees are one of many search-tree schemes that are "balanced" in order to
/// guarantee that basic dynamic-set operations take O(lg n) time in the worst case.
///
/// Notice, a null leaf node or parent node is colored black.
///
/// More details please find in chapter 13, Introduction to Algorithms, Second Edition
/// by Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein ISBN:0262032937
/// The MIT Press © 2001 (1180 pages)
/// </summary>
/// <typeparam name="T">RedBlackTreeNode type</typeparam>
/// <typeparam name="S">IComparable type</typeparam>
public class RedBlackTree<T, S>
where T : RedBlackTreeNode<S>
where S : DuplicatableKey, new()
{
private RedBlackTreeNode<S> root;
public int OSRank(RedBlackTreeNode<S> node)
{
//var node = FindNode(key);
int rank = (node.LeftChild == null ? 0 : node.LeftChild.Value.Size) + 1;
var y = node;
while (y != root)
{
if (y == y.ParentNode.RightChild)
{
rank += (y.ParentNode.LeftChild == null ? 0 : y.ParentNode.LeftChild.Value.Size) + 1;
}
y = y.ParentNode;
}
return rank;
}
/// <summary>
/// Insert a new node, at first initialize the new node as red to keep the black height
/// rule of red black tree. Insert the new node to proper position accordding to its value,
/// the fix the tree according to the defination of red black tree.
/// </summary>
/// <param name="nodeValue"></param>
public RedBlackTreeNode<S> InsertNode(S nodeValue)
{
RedBlackTreeNode<S> newNode = new RedBlackTreeNode<S>(nodeValue);
//RedBlackTreeNode<S> currentNode = newNode;
//RedBlackTreeNode<S> NIL = new RedBlackTreeNode<S>(new S());
//newNode.LeftChild = NIL;
//newNode.RightChild = NIL;
if (root == null)
{
root = newNode;
}
else
{
RedBlackTreeNode<S> tempX = root;
RedBlackTreeNode<S> tempY = null;
while (tempX != null)
{
tempY = tempX;
tempX = nodeValue.CompareTo(tempX.Value) > 0 ? tempX.RightChild : tempX.LeftChild;
}
if (nodeValue.CompareTo(tempY.Value) >= 0)
{
tempY.RightChild = newNode;
}
else
{
tempY.LeftChild = newNode;
}
}
UpdateSubTreeSize(newNode);
InsertFixup(newNode);
return newNode;
}
private void UpdateSubTreeSize(RedBlackTreeNode<S> node)
{
while (node.ParentNode != null)
{
node.ParentNode.Value.Size++;
node = node.ParentNode;
}
}
/// <summary>
/// Delete node.
/// If the node only have one or no child, just delete it.
/// If the node has both left and right children, find its successor, delete it and copy its
/// value to the node to be deleted.
/// After deleting, fix up the tree according to defination.
/// </summary>
/// <param name="node"></param>
public void DeleteNode(T node)
{
if (node == null)
return;
if ((node == root) && (root.RightChild == null) && (root.LeftChild == null))
{
root = null;
return;
}
RedBlackTreeNode<S> tempX = null, tempY = null;
if (node.LeftChild == null || node.RightChild == null)
{
tempY = node;
}
else
{
tempY = GetSuccessor(node);
}
tempX = (tempY.LeftChild != null) ? tempY.LeftChild : tempY.RightChild;
if (tempY.ParentNode == null)
root = tempX;
else
{
if (tempY == tempY.ParentNode.LeftChild)
{
tempY.ParentNode.LeftChild = tempX;
}
else
{
tempY.ParentNode.RightChild = tempX;
}
}
if (tempY != node)
{
node.Value = tempY.Value;
}
// if black node is deleted the black height rule must be violated, fix it.
if (tempY.Color == NodeColor.Black)
DeleteFixup(tempX, tempY.ParentNode);
}
/// <summary>
/// Find the node with specified value.
/// </summary>
/// <param name="value">specified value</param>
/// <returns></returns>
public RedBlackTreeNode<S> FindNode(S value)
{
RedBlackTreeNode<S> temp = root;
if (root == null)
{
return null;
}
do
{
if (value.CompareTo(temp.Value) == 0)
{
return temp;
}
else if (temp.LeftChild != null && value.CompareTo(temp.Value) < 0)
{
temp = temp.LeftChild;
}
else if (temp.RightChild != null && value.CompareTo(temp.Value) > 0)
{
temp = temp.RightChild;
}
else
{
return null;
}
} while (true);
}
/// <summary>
/// Find the successer of specific node,
/// if the right child is not empty, the successor is the far left node of the subtree.
/// If it has a successor and its right child is null, the successor must be the nearest
/// ancestor, and the left child of the successor is ancestor of the specific node.
/// </summary>
/// <param name="currentNode">the specific node </param>
/// <returns></returns>
private RedBlackTreeNode<S> GetSuccessor(RedBlackTreeNode<S> currentNode)
{
RedBlackTreeNode<S> temp = null;
if (currentNode.RightChild != null)
{
temp = currentNode.RightChild;
while (temp.LeftChild != null)
{
temp = temp.LeftChild;
}
return temp;
}
else
{
while (temp.ParentNode != null)
{
if (temp == temp.ParentNode.LeftChild)
{
return temp.ParentNode;
}
else
{
temp = temp.ParentNode;
}
}
return null;
}
}
/// <summary>
/// Fix up red black tree after inserting node. Three cases:
/// 1) the uncle of the node is red;
/// 2) the uncle of the node is black and the node is right child(left rotate to case 3);
/// 3) the uncle of the node is black and the node is left child;
/// </summary>
/// <param name="node"></param>
private void InsertFixup(RedBlackTreeNode<S> node)
{
RedBlackTreeNode<S> temp = null;
while (node != root && node.ParentNode.Color == NodeColor.Red)
{
if (node.ParentNode == node.ParentNode.ParentNode.LeftChild)
{
temp = node.ParentNode.ParentNode.RightChild;
if (temp != null && temp.Color == NodeColor.Red)
{
node.ParentNode.Color = NodeColor.Black;
temp.Color = NodeColor.Black;
node.ParentNode.ParentNode.Color = NodeColor.Red;
node = node.ParentNode.ParentNode;
}
else
{
if (node == node.ParentNode.RightChild)
{
node.ParentNode.Value.Size = (node.ParentNode.LeftChild == null ? 0 : node.ParentNode.LeftChild.Value.Size) + (node.LeftChild == null ? 0 : node.LeftChild.Value.Size) + 1;
node.Value.Size = (node.RightChild == null ? 0 : node.RightChild.Value.Size) + (node.ParentNode == null ? 0 : node.ParentNode.Value.Size) + 1;
node = node.ParentNode;
LeftRotate(node);
}
node.ParentNode.ParentNode.Value.Size = (node.ParentNode.ParentNode.RightChild == null ? 0 : node.ParentNode.ParentNode.RightChild.Value.Size) + (node.ParentNode.RightChild == null ? 0 : node.ParentNode.RightChild.Value.Size) + 1;
node.ParentNode.Value.Size = node.Value.Size + node.ParentNode.ParentNode.Value.Size + 1;
node.ParentNode.Color = NodeColor.Black;
node.ParentNode.ParentNode.Color = NodeColor.Red;
RightRotate(node.ParentNode.ParentNode);
}
}
else
{
temp = node.ParentNode.ParentNode.LeftChild;
if (temp != null && temp.Color == NodeColor.Red)
{
node.ParentNode.Color = NodeColor.Black;
temp.Color = NodeColor.Black;
node.ParentNode.ParentNode.Color = NodeColor.Red;
//node.Value.Size = 1;
//UpdateSubTreeSize(node);
node = node.ParentNode.ParentNode;
}
else
{
if (node == node.ParentNode.LeftChild)
{
node.ParentNode.Value.Size = (node.ParentNode.RightChild == null ? 0 : node.ParentNode.RightChild.Value.Size) + (node.RightChild == null ? 0 : node.RightChild.Value.Size) + 1;
node.Value.Size = (node.LeftChild == null ? 0 : node.LeftChild.Value.Size) + node.ParentNode.Value.Size + 1;
node = node.ParentNode;
RightRotate(node);
}
node.ParentNode.Color = NodeColor.Black;
node.ParentNode.ParentNode.Color = NodeColor.Red;
node.ParentNode.ParentNode.Value.Size = (node.ParentNode.ParentNode.LeftChild == null ? 0 : node.ParentNode.ParentNode.LeftChild.Value.Size) + (node.ParentNode.LeftChild == null ? 0 : node.ParentNode.LeftChild.Value.Size) + 1;
node.ParentNode.Value.Size = node.Value.Size + node.ParentNode.ParentNode.Value.Size + 1;
LeftRotate(node.ParentNode.ParentNode);
}
}
}
root.Color = NodeColor.Black;
}
/// <summary>
/// Fix up tree property after delete node from tree
/// 1) node's sibling w is red;
/// 2) node's sibling w is black, and both of w's children are black;
/// 3) node's sibling w is black, w's left child is red, and w's right child is black;
/// 4) node's sibling w is black, and w's right child is red
/// </summary>
/// <param name="node"></param>
private void DeleteFixup(RedBlackTreeNode<S> node, RedBlackTreeNode<S> parentNode)
{
RedBlackTreeNode<S> tempX = null;
while (node != root && (node == null || node.Color == NodeColor.Black))
{
if (node == parentNode.LeftChild)
{
tempX = parentNode.RightChild;
if (tempX != null && tempX.Color == NodeColor.Red)
{
tempX.Color = NodeColor.Black;
node.ParentNode.Color = NodeColor.Red;
LeftRotate(node.ParentNode);
}
else
{
if ((tempX.LeftChild == null && tempX.RightChild == null)
|| (tempX.LeftChild.Color == NodeColor.Black && tempX.RightChild.Color == NodeColor.Black))
{
tempX.Color = NodeColor.Red;
node = parentNode;
parentNode = node.ParentNode;
}
else
{
if (tempX.RightChild == null || tempX.RightChild.Color == NodeColor.Black)
{
if (tempX.RightChild != null)
{
tempX.LeftChild.Color = NodeColor.Black;
tempX.Color = NodeColor.Red;
}
RightRotate(tempX);
tempX = parentNode.RightChild;
}
tempX.Color = parentNode.Color;
parentNode.Color = NodeColor.Black;
tempX.RightChild.Color = NodeColor.Black;
LeftRotate(parentNode);
node = root;
}
}
}
else
{
tempX = parentNode.LeftChild;
if (tempX != null && tempX.Color == NodeColor.Red)
{
tempX.Color = NodeColor.Black;
parentNode.Color = NodeColor.Red;
RightRotate(parentNode);
}
else
{
if ((tempX.LeftChild == null && tempX.RightChild == null)
|| (tempX.LeftChild.Color == NodeColor.Black && tempX.RightChild.Color == NodeColor.Black))
{
tempX.Color = NodeColor.Red;
node = parentNode;
parentNode = node.ParentNode;
}
else
{
if (tempX.RightChild == null || tempX.RightChild.Color == NodeColor.Black)
{
if (tempX.RightChild != null)
{
tempX.RightChild.Color = NodeColor.Black;
tempX.Color = NodeColor.Red;
}
LeftRotate(tempX);
tempX = parentNode.LeftChild;
}
tempX.Color = parentNode.Color;
parentNode.Color = NodeColor.Black;
tempX.LeftChild.Color = NodeColor.Black;
RightRotate(parentNode);
node = root;
}
}
}
}
node.Color = NodeColor.Black;
}
/// <summary>
/// Right rotate the node, used when fix up tree property
/// </summary>
/// <param name="node"></param>
private void RightRotate(RedBlackTreeNode<S> node)
{
if (node.LeftChild == null)
return;
RedBlackTreeNode<S> child = node.LeftChild;
if (node.ParentNode != null)
{
if (node.ParentNode.LeftChild != null && node.ParentNode.LeftChild == node)
{
node.ParentNode.LeftChild = child;
}
else
{
node.ParentNode.RightChild = child;
}
}
else
{
node.LeftChild.ParentNode = null;
}
node.LeftChild = child.RightChild;
child.RightChild = node;
RecheckRoot();
}
/// <summary>
/// Left rotate the node, used when fix up tree property
/// </summary>
/// <param name="node"></param>
private void LeftRotate(RedBlackTreeNode<S> node)
{
if (node.RightChild == null)
return;
RedBlackTreeNode<S> child = node.RightChild;
if (node.ParentNode != null)
{
if (node.ParentNode.LeftChild != null && node.ParentNode.LeftChild == node)
{
node.ParentNode.LeftChild = child;
}
else
{
node.ParentNode.RightChild = child;
}
}
else
{
node.RightChild.ParentNode = null;
}
node.RightChild = child.LeftChild;
child.LeftChild = node;
RecheckRoot();
}
/// <summary>
/// the rotation may change the root, check and reset the root node.
/// </summary>
private void RecheckRoot()
{
while (root.ParentNode != null)
{
root = root.ParentNode;
}
}
}
public class RedBlackTreeNode<T> where T : IComparable<DuplicatableKey>
{
private T value;
public T Value
{
get { return this.value; }
set { this.value = value; }
}
private NodeColor color;
public NodeColor Color
{
get { return color; }
set { color = value; }
}
private RedBlackTreeNode<T> leftChild;
public RedBlackTreeNode<T> LeftChild
{
get { return leftChild; }
set
{
if (value != null)
value.ParentNode = this;
leftChild = value;
}
}
private RedBlackTreeNode<T> rightChild;
public RedBlackTreeNode<T> RightChild
{
get { return rightChild; }
set
{
if (value != null)
value.ParentNode = this;
rightChild = value;
}
}
private RedBlackTreeNode<T> parentNode;
public RedBlackTreeNode<T> ParentNode
{
get { return parentNode; }
set { parentNode = value; }
}
public RedBlackTreeNode(T nodeValue)
{
value = nodeValue;
color = NodeColor.Red;
}
}
}
时间效率C#:
2. 逆序数思想使用归并排序。
using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Collections.Generic;
//https://www.hackerrank.com/challenges/insertion-sort
namespace Sort_Insertion_Sort_Advanced_Analysis
{
class Program
{
static void Main(string[] args)
{
using (System.IO.TextReader streamReader =
new StreamReader("input04.txt"))
{
int T = int.Parse(streamReader.ReadLine());
for (int i = 0; i < T; i++)
{
int N = int.Parse(streamReader.ReadLine());
String[] stringValues = streamReader.ReadLine().Split(' ');
int[] intValues = Array.ConvertAll(stringValues, int.Parse);
CountStepsMergeSort(intValues);
Console.WriteLine(count);
count = 0;
}
Console.ReadKey();
}
}
private static long count = 0;
private static void CountStepsMergeSort(int[] intValues)
{
int length = intValues.Length;
MergeSort(intValues, 0, length - 1);
}
private static void MergeSort(int[] intValues, int p1, int p2)
{
if (p1 >= p2) return;
int mid = p1 + ((p2 - p1) >> 1);
MergeSort(intValues, p1, mid);
MergeSort(intValues, mid + 1, p2);
Merge(intValues, p1, mid, p2);
}
private static void Merge(int[] intValues, int p1, int mid, int p2)
{
int i = p1, j = mid +1;
Queue<int> queue = new Queue<int>();
while (i <= mid && j <= p2)
{
if (intValues[i] <= intValues[j])
{
queue.Enqueue(intValues[i++]);
}
else
{
queue.Enqueue(intValues[j++]);
count += mid - i + 1;
}
}
while (j <= p2)
{
queue.Enqueue(intValues[j++]);
}
while (i <= mid)
{
queue.Enqueue(intValues[i++]);
}
for (int k = p1; k <= p2; k++)
{
intValues[k] = queue.Dequeue();
}
}
}
时间效率C#:
3. 逆序数思想使用树状数组。
4.线段树http://dongxicheng.org/structure/segment-tree/