《剑指Offer》面试题的C#解法

面试题2:单例模式

    class SingleTon
	{
		public SingleTon Instance()
		{
			return Nested.instance;
		}
		
		private class  Nested
		{
			internal static readonly SingleTon instance = new SingleTon();
		}
	}

要点:静态变量/函数只会在程序运行时执行一次。


面试题3:找出数组中重复的数字

        public void Problem3()
        {
            HashSet result = new HashSet();
            int[] input = {2,6,5,7,1,2,3,4,8};
            for (int i = 0; i < input.Length; i++)
			{
                int value = input[i];
                while (input[i] != i)
                {
                    if (input[value] != value)
                    {
                        int temp = input[i];
                        input[i] = input[value];
                        input[value] = temp;
                        value = input[i];
                    }
                    else
                    {
                        result.Add(value);
                        break;
                    }
                }
            }
            foreach (int value in result)
            {
                Console.WriteLine(value);
            }
        }

面试题3-2:在不改动原数组的前提下,找出重复的数字

        public void Problem3_2()
		{
			int? result = null;
			int num = 0;
			int[] array = { 2, 3, 5, 4, 3, 2, 6, 7 };
			int start = 0, end = array.Length - 1;
			while (end >= start)
			{
				int mid = (end - start)>>1 + start;
				int count = GetCount(array, start, mid);
				if (end == start)
				{
					if (count > 1)
					{
						result = array[start];
						num = count;
					}
					break;
				}
				if (count > (mid - start + 1))
				{
					end = mid;
				}
				else
				{
					start = mid + 1;
				}
			}
			if (result == null)
			{
				Console.WriteLine("没有重复的数字");
			}
			else
			{
				Console.WriteLine(result + "重复了{0}次", num);
			}
		}

		private int GetCount(int[] array, int start, int end)
		{
			int count = 0;
			for (int i = 0; i < array.Length; i++)
			{
				for (int j = start; j <= end; j++)
				{
					if (array[i] == array[j])
					{
						count++;
					}
				}
			}
			return count;
		}

面试题4:在二维数组中查找数字

        public bool Problem4(int target)
		{
			int[,] input = {
				{ 1,2,3},
				{ 2,4,6},
				{ 3,6,9},
			};
			bool result = false;
			int col = input.GetUpperBound(0) + 1;
			int row = input.GetLength(0);
			//从右上开始遍历
			int c = col - 1;//列
			int r = 0;//行
			while (c < 0 || r > row - 1)
			{
				int value = input[c, r];
				if (value == target)
				{
					result = true;
					break;
				}
				else if (value > target)
				{
					c--;
				}
				else
				{
					r++;
				}
			}
			Console.WriteLine(result);
			return result;
		}

要点:从右上角或者左下角开始比较,才可以在每次比较中缩小查询的区域。


面试题5:将字符串中的空格提替换成指定字符

        public string Problem5(string input, string target)
		{
			if (input.Length == 0)
			{
				return "";
			}
			int count = 0;
			foreach (var c in input)
			{
				if (c == ' ')
				{
					count++;
				}
			}
			char[] chars = new char[input.Length + count * (target.Length - 1)];
			int p = chars.Length - 1;
			for (int i = input.Length - 1; i >= 0; i--)
			{
				if (input[i] != ' ')
				{
					chars[p--] = input[i];
				}
				else
				{
					for (int j = target.Length - 1; j >= 0; j--)
					{
						chars[p--] = target[j];
					}
				}
			}
			return new string(chars);
		}

要点:从后往前替换。


面试题6:从尾到头打印链表

		//用栈实现
		public void Problem6_1(ListNode Head)
		{
			if (Head == null)
			{
				return;
			}
			Stack stack = new Stack();
			while (Head.Next != null)
			{
				stack.Push(Head.Value);
				Head = Head.Next;
			}
			stack.Push(Head.Value);
			while (stack.Count > 0)
			{
				Console.WriteLine(stack.Pop());
			}
		}
		//用递归实现
		public void Problem6_2(ListNode Head)
		{
			if (Head == null)
				return;
			if (Head.Next != null)
				Problem6_2(Head.Next);
			Console.Write(Head.Value);
		}

要点:递归的本质就是栈结构。


面试题7:给定前序遍历序列和中序遍历序列输出后续遍历序列。

        public void Problem7()
        {
            //输入前序遍历序列
            int[] input1 = { 1, 2, 4, 7, 3, 5, 6, 8 };
            //输入中序遍历序列
            int[] input2 = { 4, 7, 2, 1, 5, 3, 8, 6 };
            Tree root = Problem7_Solution(input1, input2, 0, 0, input1.Length - 1);
            //输出后续遍历序列
            OutPut(root);
        }

        private void OutPut(Tree tree)
        {
            if (tree == null)
                return;
            OutPut(tree.LeftNode);
            OutPut(tree.RightNode);
            Console.WriteLine(tree.Value);
        }

        private Tree Problem7_Solution(int[] input1, int[] input2, int root_pos, int start_pos, int end_pos)
        {
            if (end_pos < start_pos || root_pos > input1.Length)
                return null;

            Tree tree = new Tree(input1[root_pos]);
            if (start_pos == end_pos)
                return tree;

            int i;
            for (i = start_pos; i <= end_pos; i++)
            {
                if (input2[i] == tree.Value)
                {
                    break;
                }
            }

            int left_num = i - start_pos;

            int LeftRootPos = root_pos + 1;
            tree.LeftNode = Problem7_Solution(input1, input2, LeftRootPos, start_pos, i - 1);

            int RightRootPos = root_pos + left_num + 1;
            tree.RightNode = Problem7_Solution(input1, input2, RightRootPos, i + 1, end_pos);

            return tree;
        }
------------------------------------------------------------------------------
    class Tree
    {
        public int Value;
        public Tree LeftNode;
        public Tree RightNode;
        public Tree(int value) { Value = value; }
    }

面试题8:二叉树的下一个节点,给定中序遍历序列找出下一个节点。

    public class TreeNode
	{
		public TreeNode()
		{
			Value = "";
		}
		public TreeNode(string value)
		{
			Value = value;
		}
		public string Value { get; set; }
		public TreeNode LeftNode { get; set; }
		public TreeNode RightNode { get; set; }
		public TreeNode ParentNode { get; set; }
	}
----------------------------------------------------------------------------------------
    public class solution
    {
        public TreeNode Problem8_FindNextNode(TreeNode tree, TreeNode node)
		{
			if (tree == null || node == null)
				return null;

			TreeNode result = new TreeNode();
			if (node.RightNode != null)
			{
				result = node.RightNode;
				while (result.LeftNode != null)
				{
					result = result.LeftNode;
				}
			}
			else
			{
				if (node.ParentNode.LeftNode == node)
				{
					result = node.ParentNode;
				}
				else
				{
					while (node.ParentNode != null && node.ParentNode.RightNode == node)
					{
						node = node.ParentNode;
					}
					result = node.ParentNode;
				}
			}
			Console.Write(result == null ? "" : result.Value);
			return result;
		}
    }

面试题9:用两个栈实现队列

    public class MyQueue
    {
        Stack stack1 = new Stack();
        Stack stack2 = new Stack();
        public int Count
        {
            get;
            private set;
        }

        public void Clear()
        {
            stack1.Clear();
            stack2.Clear();
            Count = 0;
        }

        public bool Contains(T target)
        {
            return stack1.Contains(target) || stack2.Contains(target);
        }

        public T Dequeue()
        {
            if (Count <= 0)
            {
                return default(T);
            }
            Count--;
            if (stack1.Count != 0)
            {
                while (stack1.Count != 0)
                {
                    stack2.Push(stack1.Pop());
                }
                return stack2.Pop();
            }
            else
            {
                while (stack2.Count != 0)
                {
                    stack1.Push(stack2.Pop());
                }
                return stack1.Pop();
            }
        }

        public void Enqueue(T target)
        {
            Count++;
            if (stack1.Count != 0)
            {
                stack1.Push(target);
            }
            else
            {
                stack2.Push(target);
            }
        }

        public T[] ToArray()
        {
            T[] array = new T[Count];
            if (stack1.Count != 0)
            {
                return array = stack1.ToArray();
            }
            else
            {
                return array = stack2.ToArray();
            }
        }

补充:用两个队列实现栈,思路:将第一个队列内的n-1个元素移动到第二个队列后,弹出队列中剩下的唯一一个元素。


面试题10:斐波那契数列

        public int Problem10(int n)
        {
            if (n <= 0)
                return 0;

            if (n == 1)
                return 1;

            return Problem10(n - 1) + Problem10(n - 2);
        }

面试题11:旋转数组的最小数字

        //Problem11 旋转有一定排序的数组的最小数字 如[3,4,5,1,2] -> return 3
		public int Problem11(int[] array)
		{
			int start = 0;
			int mid = start;
			int end = array.Length - 1;
			if (array[start] < array[end])
			{
				return start;
			}
			while (end - start > 1 && array[start] == array[end])
			{
				start++;
			}
			while (end - start > 1)
			{
				mid = (start + end) / 2;
				if (array[start] <= array[mid])
				{
					start = mid;
				}
				else if (array[mid] <= array[end])
				{
					end = mid;
				}
			}
			return end;
		}

面试题12:矩阵中的路径

		//Problem12 矩阵中的路径
		#region Problem12

		private char[] array;
		private int[,] result_index;
		public bool Problem12(char[,] matrix, string target)
		{
			int row_length = matrix.GetLength(0);
			int col_length = matrix.GetLength(1);
			array = target.ToCharArray();
			bool[,] visited = new bool[row_length, col_length];
			result_index = new int[array.Length, 2];
			bool hasPath = false;
			for (int row = 0; row < row_length; row++)
			{
				for (int col = 0; col < col_length; col++)
				{
					if (FindStrInMatrix(matrix, row, col, row_length, col_length, 0, visited))
					{
						hasPath = true;
						break;
					}
				}
			}

			Console.WriteLine(hasPath ? "Find Success" : "Find False");
			if (hasPath)
			{
				for (int i = 0; i < result_index.GetLength(0); i++)
				{
					for (int j = 0; j < 2; j++)
					{
						Console.Write(result_index[i, j] + " ");
					}
					Console.WriteLine();
				}
			}
			
			return hasPath;
		}
		public bool FindStrInMatrix(char[,] matrix, int row, int col, int row_length, int col_length, int char_index, bool[,] visited)
		{
			if (char_index >= array.Length)
			{
				return true;
			}

			bool result = false;
			if (row >= 0 && col >= 0 && row < row_length && col < col_length && matrix[row, col] == array[char_index] && !visited[row, col])
			{
				visited[row, col] = true;
				result_index[char_index, 0] = row;
				result_index[char_index, 1] = col;
				char_index++;

				result = FindStrInMatrix(matrix, row - 1, col, row_length, col_length, char_index, visited)
					 || FindStrInMatrix(matrix, row + 1, col, row_length, col_length, char_index, visited)
					 || FindStrInMatrix(matrix, row, col - 1, row_length, col_length, char_index, visited)
					 || FindStrInMatrix(matrix, row, col + 1, row_length, col_length, char_index, visited);

				if (!result)
				{
					char_index--;
					visited[row, col] = false;
					result_index[char_index, 0] = 0;
					result_index[char_index, 1] = 0;
				}
			}

			return result;
		}
		#endregion

面试题13:机器人的运动范围

        #region 机器人的运动范围
        public void Problem13(int m, int n, int k)
        {
            if (m <= 0 || n <= 0)
            {
                return;
            }

            visited = new bool[m, n];
            for (int i = 0; i < m; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    visited[i, j] = false;
                }
            }

            Console.WriteLine(Move(0, 0, m, n, k));
        }

        private bool[,] visited;
        private int Move(int i, int j, int m, int n, int k)
        {
            if (!Check(i, j, m, n, k))
            {
                return 0;
            }

            if (visited[i, j])
            {
                return 0;
            }

            visited[i, j] = true;

            int count = 1;
            //向上
            count += Move(i, j - 1, m, n, k);

            //向下
            count += Move(i, j + 1, m, n, k);

            //向左
            count += Move(i - 1, j, m, n, k);

            //向右
            count += Move(i + 1, j, m, n, k);

            return count;
        }

        private bool Check(int i, int j, int m, int n, int k)
        {
            if (i < 0 || j < 0 || i >= m || j >= n)
            {
                return false;
            }

            int total = i % 10 + i / 10 + j % 10 + j / 10;
            Console.WriteLine("i:{0},j:{1},total:{2}", i, j, total);
            return k >= total;
        }
        #endregion

面试题14:剪绳子 长度为n的绳子 剪成若干单位为1的绳 求长度乘积最大的值

        #region Problem14
		//动态规划
		public int Problem14_1(int length)
		{
			if (length <= 1) return 0;
			if (length == 2) return 1 * (2 - 1);
			if (length == 3) return 2 * (3 - 2);
			int[] max_array = new int[length];
			max_array[0] = 0;
			max_array[1] = 0;
			max_array[2] = 1;
			max_array[3] = 2;
			int max = 0;
			for (int i = 4; i <= length; i++)
			{
				max = 0;
				for (int j = 1; j <= i / 2; j++)
				{
					int cur_value = max_array[j] * max_array[i - j];
					if (cur_value > max)
					{
						max = cur_value;
					}
				}
				max_array[i] = max;
			}
			return max;
		}
		//贪婪算法
		public int Problem14_2(int length)
		{
			if (length <= 1) return 0;
			if (length == 2) return 1 * (2 - 1);
			if (length == 3) return 2 * (3 - 2);
			int time_of_3 = length / 3;
			if (length - time_of_3 * 3 == 1)
			{
				time_of_3 -= 1;
			}
			length -= time_of_3 * 3;
			int time_of_2 = length / 2;
			int max = (int)(Math.Pow(3, time_of_3) * Math.Pow(2, time_of_2));
			return max;
		}
		#endregion

要点:

可以使用动态规划来解决问题的特点:

1.目标是求解最优解

2.整体问题的最优解依赖于子问题的最优解

3.可以将问题分成若干子问题且子问题之间还有重叠的部分

4.从上往下分析问题,从下往上解决问题


面试题16:数值的整数次方

        public double Power(double x, int y)
        {
            double result = 0;
            int abs_y = Math.Abs(y);
            if (abs_y == 0)
            {
                result = 0;
                return y >= 0 ? result : 1 / result;
            }

            if (abs_y == 1)
            {
                result = x;
                return y >= 0 ? result : 1 / result;
            }

            if ((abs_y & 0x1) == 0)  // %2 -> &0x1
            {
                result = Power(x, abs_y >> 1) * Power(x, abs_y >> 1); //  /2 -> >>1
            }
            else
            {
                result = x * Power(x, (abs_y - 1) / 2) * Power(x, (abs_y - 1) / 2);
            }
            return y >= 0 ? result : 1 / result;
        }

 

你可能感兴趣的:(C#)