C#经典算法面试题

网络上收集的一些C#经典算法面试题,分享给大家

# 递归算法

## C#递归算法计算阶乘的方法

> 一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!。1808年,基斯顿·卡曼引进这个表示法。

原理:亦即n!=1×2×3×...×(n-1)×n。阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n。

/// <summary>
        /// C#递归算法计算阶乘的方法
        /// 一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!。1808年,基斯顿·卡曼引进这个表示法。
        /// 亦即n!=1×2×3×...×(n-1)×n。阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n。
        /// 最终输出结果:120
        /// </summary>
        public static void RecursiveFactorial()
        {
            int result = Factorial(5);
            Console.WriteLine("5的阶乘为:" + result);//5!=120
        }

        public static int Factorial(int n)
        {
            if (n == 0 || n == 1)
            {
                return 1;
            }
            else
            {
                // 递归调用:当前数n乘以前面所有数的阶乘
                return n * Factorial(n - 1);
            }
        }

 ## C#递归算法数组求

/// <summary>
        /// 递归算法数组求
        /// 最终输出结果为:259
        /// </summary>
        public static void RecursiveArraySum()
        {
            int[] numbers = { 1, 88, 66, 4, 100 };
            int sum = ArraySum(numbers, 0);
            Console.WriteLine("数组元素的总和为:" + sum);
        }

        /// <summary>
        /// 计算数组元素的总和
        /// </summary>
        /// <param name="arr">arr</param>
        /// <param name="index">index</param>
        /// <returns></returns>
        public static int ArraySum(int[] arr, int index)
        {
            if (index >= arr.Length)
            {
                // 基本情况:数组为空或者已经遍历完所有元素
                return 0;
            }
            else
            {
                // 递归调用:当前元素加上剩余元素的总和
                return arr[index] + ArraySum(arr, index + 1);
            }
        }

## C#使用递归算法来实现求解斐波纳契数列中第30位数的值

> 一列数的规则如下 : 1 、 1 、 2 、 3 、 5 、 8 、 13 、 21 、 34… 求第 30 位数是多少, 用递归算法实现。

/// <summary>
        /// 使用递归算法来实现求解斐波纳契数列中第30位数的值
        /// 一列数的规则如下 : 1 、 1 、 2 、 3 、 5 、 8 、 13 、 21 、 34… 求第 30 位数是多少, 用递归算法实现
        /// 最终输出结果为:832040
        /// </summary>
        public static void FibonacciSum()
        {
            int n = 30;
            int result = Fibonacci(n);
            Console.WriteLine("第 " + n + "位斐波那契数是:" + result);
        }

        public static int Fibonacci(int n)
        {
            if (n <= 0)
            {
                return 0;
            }
            else if (n > 0 && n <= 2)
            {
                return 1;
            }
            else
            {
                // 递归情况:调用自身计算前两个数字之和
                return Fibonacci(n - 1) + Fibonacci(n - 2);
            }
        }

## 使用C#语言编写的递归算法来计算1+2+3+4+…+100的结果

/// <summary>
        /// 使用C#语言编写的递归算法来计算1+2+3+4+…+100的结果
        /// 最终输出结果是:5050
        /// </summary>
        public static void RecursiveAlgorithmSum()
        {
            int result = SumNumbers(100);
            Console.WriteLine("1+2+3+4+...+100 = " + result);
        }

        public static int SumNumbers(int n)
        {
            if (n == 1)
            {
                return 1;//递归结束条件
            }
            else
            {
                return n + SumNumbers(n - 1);
            }
        }

# C#常见排序算法

## 冒泡排序算法

### 双重循环方式实现冒泡排序

/// <summary>
        /// 双重循环方式实现冒泡排序
        /// </summary>
        public static void BubbleSort()
        {
            int[] arr = { 1, 8, 9, 5, 6, 2, 3, 4, 7 };
            int arrLength = arr.Length;
            for (int i = 0; i < arrLength - 1; i++)
            {
                for (int j = 0; j < arrLength - i - 1; j++)
                {
                    if (arr[j] > arr[j + 1])
                    {
                        //交换arr[j]和arr[j+1]的值
                        int temp = arr[j];
                        arr[j] = arr[j + 1];
                        arr[j + 1] = temp;
                    }
                }
            }

            Console.WriteLine("排序后结果:" + string.Join(", ", arr));
        }

 

 ### 递归方式实现冒泡排序

/// <summary>
        /// 递归方式实现冒泡排序
        /// </summary>
        /// <param name="arr">arr</param>
        /// <param name="arrLength">arrLength</param>
        public static void RecursiveBubbleSort(int[] arr, int arrLength)
        {
            if (arrLength == 1)
                return;

            for (int i = 0; i < arrLength - 1; i++)
            {
                if (arr[i] > arr[i + 1])
                {
                    //交换arr[i]和arr[i+1]的值
                    int temp = arr[i];
                    arr[i] = arr[i + 1];
                    arr[i + 1] = temp;
                }
            }

            RecursiveBubbleSort(arr, arrLength - 1);
        }

        public static void RecursiveBubbleSortRun()
        {
            int[] arr = { 1, 8, 9, 5, 6, 2, 3, 4, 7 };
            int arrLength = arr.Length;
            RecursiveBubbleSort(arr, arrLength);
            Console.WriteLine("排序后结果:" + string.Join(", ", arr));
        }

## 选择排序算法

> 选择排序是一种简单直观的排序算法,它的工作原理如下:

> 选择排序算法的核心思想是每次从未排序的部分中找到最小元素,然后将其与未排序部分的第一个元素交换位置。通过不断进行这个过程,逐步将最小元素放到正确的位置,完成整个数组的排序。

public class 选择排序算法
    {
        /// <summary>
        /// 选择排序算法
        /// 选择排序算法的核心思想是每次从未排序的部分中找到最小元素,然后将其与未排序部分的第一个元素交换位置。
        /// 通过不断进行这个过程,逐步将最小元素放到正确的位置,完成整个数组的排序。
        /// </summary>
        public static void SelectionSortAlgorithmMain()
        {
            int[] array = { 64, 25, 12, 22, 11 };

            Console.WriteLine("原始数组: ");
            PrintArray(array);

            SelectionSortAlgorithm(array);

            Console.WriteLine("排序后的数组: ");
            PrintArray(array);
        }

        static void SelectionSortAlgorithm(int[] arr)
        {
            int n = arr.Length;

            for (int i = 0; i < n - 1; i++)
            {
                // 在未排序部分中找到最小元素的索引
                int minIndex = i;
                for (int j = i + 1; j < n; j++)
                {
                    if (arr[j] < arr[minIndex])
                    {
                        minIndex = j;
                    }
                }

                // 将最小元素与未排序部分的第一个元素交换位置
                int temp = arr[minIndex];
                arr[minIndex] = arr[i];
                arr[i] = temp;
            }
        }

        static void PrintArray(int[] arr)
        {
            int n = arr.Length;
            for (int i = 0; i < n; ++i)
            {
                Console.Write(arr[i] + " ");
            }
            Console.WriteLine();
        }
    }

 

# C#List集合相关

## C#List RemoveAt(按照索引移除)、Remove(按照对象移除)

/// <summary>
        /// 获取移除后的列表数据
        /// 考察内容:C#List RemoveAt(按照索引移除)、Remove(按照对象移除)
        /// </summary>
        /// <returns></returns>
        public static List<int> GetAfterRemoveListData()
        {
            List<int> list = new List<int>();
            for (int i = 1; i <= 10; i++)
            {
                list.Add(i);
            }

            for (int i = 0; i < 5; i++)
            {
                list.RemoveAt(i);//单独使用输出结果:2,4,6,8,10,按照索引移除
                list.Remove(i);//单独使用输出结果:5,6,7,8,9,10,按照对象移除
            }

            //以上两种同时使用时输出结果:6,7,9
            return list;
        }

 

# 其他算法

## 实现一个方法,对于输入的任意字符串,统计出其中每一种字符出现的次数

```C#

/** 字典的定义

 必须包含名空间System.Collection.Generic

 Dictionary里面的每一个元素都是一个键值对(由二个元素组成:键和值)

 键必须是唯一的,而值不需要唯一的

 键和值都可以是任何类型(比如:string, int, 自定义类型,等等)

 通过一个键读取一个值的时间是接近O(1)

 键值对之间的偏序可以不定义

*/

static void CountChar(string str)
{
    Dictionary<char, int> dic = new Dictionary<char, int>();
    foreach (char c in str)
    {
        if (dic.ContainsKey(c))
            dic[c]++;
        else
            dic.Add(c, 1);
    }
    foreach (KeyValuePair<char, int> p in dic)
    {
        Console.WriteLine("字符{0},出现的次数{1}", p.Key.ToString(), p.Value.ToString());
    }
}

 ## 实现一个将字符串转换为整数的方法,不要使用int.Parse、int.TryParse、Convert.ToInt32等任何类库方法

public static bool TryParseToInt(string strData, out int num)
        {
            if (string.IsNullOrWhiteSpace(strData))
            {
                num = 0;
                return false;
            }
            int result = 0;

            bool minus = strData[0] == '-' ? true : false;
            if (minus && strData.Length == 1)
            {
                num = 0;
                return false;
            }

            for (int i = minus ? 1 : 0; i < strData.Length; i++)
            {
                if (strData[i] >= '0' && strData[i] <= '9')
                {
                    result = strData[i] - 48 + result * 10;
                }
                else
                {
                    num = 0;
                    return false;
                }
            }

            num = minus ? -result : result;
            return true;
        }

        static void Main(string[] args)
        {
            //打印输出getValue为转化而成的整数
            var result = TryParseToInt("99", out int getValue);
        }

 ## 求以下表达式的值,写出您想到的一种或几种实现方法: 1-2+3-4+……+m

//通过顺序规律写程序,同时也知道flag标志位的重要性
  static int F1(int m)  
    {  
        int sum =0;  
        bool flag =true;  
        for (int i = 1; i <= m; i++)  
        {  
            if (flag)  //一次是默认是True,下下也为True  
                sum += i;  
            else  
                sum -= i;  
            flag = !flag;  

        }  
        return sum;  
    }  

    //通过奇偶性  
    static int F2(int m)  
    {  
        int sum = 0;  
        for (int i = 1; i <= m; i++)  
        {  
            if (i % 2 >0)  //即为奇数  
                sum += i;  
            else  
                sum -= i;  
        }  
        return sum;  
    }  

 ## 有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?

class Program  
    {  
        static void Main(string[] args)  
        {  

            //有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?  
            //分解题目  
            //条件:四个数字1、2、3、4  ;三位数:百位、十位、个位  
            //要求:互不相同;无重复数字:每个数字在三位中只出现一次  
            //结果:多少个? 都是多少?  

            int count = 0; //统计个数  
            for (int bw = 1; bw <= 4; bw++)  
            {  
                for (int sw = 1; sw <= 4; sw++)  
                {  
                    if (sw!= bw)  //很显然,只有百位和十位不同的情况下才能谈个位。  
                    {  
                        for (int gw = 1; gw <= 4; gw++)  
                        {  
                            if (gw != sw && gw != bw)   //百位用过的,十位就不能用;百位和十位都用过的,个位就不能用  
                            {  
                                count++;  
                                Console.WriteLine("{0}{1}{2}", bw, sw, gw);  
                            }  
                        }  
                    }  
                }  
            }  
            Console.WriteLine("一共有{0}个", count);  
            Console.Read();  

        }  
    }   

 

## 一个6位数乘以一个3位数,得到一个结果。但不清楚6位数的两个数字是什么,而且结果中有一位数字也不清楚,请编程找出问好代表的数字,答案可能有多个。

> 表达式:12?56?*123 = 154?4987

for (int a = 0; a < 10; a++)  
    {  
        for (int b = 0; b < 10; b++)  
        {  
            for (int c = 0; c < 10; c++)  
            {  
                if ((120560 + a + b * 1000) * 123 == 15404987 + c * 10000)  
                {  
                    Console.WriteLine(a);  
                    Console.WriteLine(b);  
                    Console.WriteLine(c);  
                }  
            }  
        }  
    }  
    Console.Read();  

 ## 有一个字符串 "I am a good man",设计一个函数,返回 "man good a am I"。

static string Reverse()  
          {  
              string s = "I am a good man";  
              string[] arr = s.Split(' ');  
              string res = "";  
              for (int i = arr.Length - 1; i >= 0; i--)  
              {  
                  res += arr[i];  
                  if (i > 0)  
                      res += " ";  
              }  
              return res;  
          }  

 ## C# 九九乘法表算法实现

static void Mu()  
          {  
              string t = string.Empty;  
              for (int i = 1; i < 10; i++)  
              {  
                  for (int j = 1; j <= i; j++)  
                  {  
                      t = string.Format("{0}*{1}={2} ", j, i, (j * i));  
                      Console.Write(t);  
                      //if (j * i < 82)  
                      //    Console.Write(" ");  
                      if (i == j)  
                          Console.Write("\n");  
                  }  
              }  
          }  

 

## 在1~10000的整数中,找出同时符合以下条件的数:a.必须是质数。b.该数字各位数字之和为偶数,如数字12345,各位数字之和为1+2+3+4+5=15,不是偶数。

> 本题考了两个地方:

> (1)、质数的理解:质数就是所有比1大的整数中,除了1和它本身外,不再有别的约数。2是一个不是奇数的质数,它既是质数也是偶数,面试者极容易忽略这点。判断数N是否为质数要直接从3开始判断(如果N不是2),首先不能是偶数,然后再判断是否能被3、5、7....整除,直到sqrt(N)止。

> (2)、求各位数字之和,可以通过循环取余的办法。

using System;  
    using System.Collections.Generic;  

    class program  
    {  
       static void Mian(string[] args)  
       {  
          int N =1000;  
          List<int> primes = new List<int>();  
          primes.Add(2);  
          Console.Write(2+" ");  
          for(int i=3;i<N,i+=2)  
          {  
              if(!)  

          }  
       }  
       static bool IsDigitSumEven(int n)  
       {  
          int sum=0;  
          while(n>0)  
         {  
             sum +=n% 10;  
             n /=10;  
         }  
         return sum%2==0;  
       }  
    }  

 

### Transformer 模型详解 #### 一、Transformer 整体架构 Transformer 是一种基于自注意力机制(Self-Attention Mechanism)的神经网络模型,旨在解决序列数据处理中的长期依赖问题。该模型摒弃了传统的循环神经网络(RNN) 和卷积神经网络(CNN),完全依靠自注意力机制来捕捉输入和输出之间的全局依赖关系[^1]。 整个架构由编码器(Encoder)和解码器(Decoder)两部分组成: - **编码器**:负责接收输入序列并将其转换成高维向量表示; - **解码器**:根据编码器产生的上下文信息生成目标序列; 两者之间通过多头自注意层(Multi-head Self-Attention Layer)连接,在每一层内部还包含了前馈神经网络(Feed Forward Neural Network, FFN)[^2]。 ```mermaid graph LR; A[Input Sequence] --> B{Encoder Stack}; subgraph Encoder Layers C[MHSA (Multi Head Self Attention)] --- D[Add & Norm]; E[FFN (Feed Forward Networks)] --- F[Add & Norm]; end G{Decoder Stack} <-- H[Memory from Encoders]; I[Output Sequence] <-- J{Decoder Layers} ``` #### 二、工作流程解析 当给定一个源语言句子作为输入时,经过分词后得到一系列token组成的列表。这些tokens会被映射到对应的嵌入(embedding)空间中形成矩阵形式的数据。随后进入多个相同的编码单元堆叠而成的编码栈内进行特征提取操作。每个编码单元主要包含两个子模块——一个多头自关注层用于计算query(Q), key(K), value(V)三者间的相似度得分,并据此调整value权重获得新的context vector; 另一个是全连接前馈网络用来进一步变换维度大小以便更好地表达语义信息。 对于翻译任务而言,则需额外构建一组类似的解码组件以逐步预测下一个可能的目标单词直至结束符为止。值得注意的是,在训练阶段为了加速收敛速度通常会采用teacher forcing技术即利用真实的上一步骤输出而非当前时刻所估计的结果参与后续迭代更新过程。 #### 三、核心特性阐述 ##### 自注意力机制 这是Transformer区别于其他传统RNN/CNN的最大亮点之一。它允许模型在同一时间步长下同时考虑所有位置的信息而不仅仅是相邻几个节点的影响范围。具体实现方式就是让每一个position都能与其他任意一处建立联系并通过softmax函数规范化后的概率分布加权求和最终得出综合考量过全部因素的新状态描述。 ##### 多头设计 考虑到单一head可能会丢失某些重要的局部模式匹配机会因此引入了multi-head策略使得不同heads可以专注于特定类型的关联性挖掘从而提高整体表现力。简单来说就是在同一层次里平行运行若干组独立却又相互补充的小规模self-attention units然后把它们各自的输出拼接起来再送往下一层继续加工处理直到最后一刻才汇总输出最终结果。 ##### 前馈神经网络 除了上述提到的核心部件之外每层还会配备有一个简单的线性变换+ReLU激活构成的标准MLP结构充当非线性的引入手段增强系统的表征能力同时也起到一定的正则化作用防止过拟合现象发生。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~风清扬~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值