基础算法问题

特别注意:动画来自https://blog.csdn.net/iechenyb/article/details/81941022?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

 

排序算法平均时间复杂度空间复杂度是否稳定 
冒泡排序 O(n2) O(1)  
选择排序 O(n2) O(1) 不是  
直接插入排序 O(n2) O(1)  
归并排序 O(nlogn) O(nlogn)  
快速排序 O(nlogn) O(logn) 不是  
堆排序 O(nlogn) O(1)  不是  
希尔排序 O(nlogn) O(1) 不是  

注:

1 归并排序可以通过手摇算法将空间复杂度降到O(1),但是时间复杂度会提高。

1.冒泡排序

for (int i = 0; i < nums.Length-1; i++)
{
     //交换的次数
    for (int j = 0; j < nums.Length-1-i; j++)
    {
        if (nums[j] > nums[j + 1])
        {
            temp = nums[j];
            nums[j] = nums[j + 1];
            nums[j + 1] = temp;
        }
    }
}

2.选择排序

 private static void SelectSort(int[] arr)
 {
     int temp = 0;
     for (int i = 0; i < arr.Length - 1; i++)
     {
         int minVal = arr[i]; //假设 i 下标就是最小的数
         int minIndex = i;  //记录我认为最小的数的下标
         for (int j = i + 1; j < arr.Length; j++)   //这里只是找出这一趟最小的数值并记录下它的下标
         {
             //说明我们认为的最小值,不是最小
             if (minVal > arr[j])    //这里大于号是升序(大于是找出最小值) 小于是降序(小于是找出最大值)
             {
                 minVal = arr[j];  //更新这趟最小(或最大)的值 (上面要拿这个数来跟后面的数继续做比较)
                 minIndex = j;    //记下它的下标
             }
         }
         //最后把最小的数与第一的位置交换
         temp = arr[i];    //把第一个原先认为是最小值的数,临时保存起来
         arr[i] = arr[minIndex];   //把最终我们找到的最小值赋给这一趟的比较的第一个位置
         arr[minIndex] = temp;  //把原先保存好临时数值放回这个数组的空地方,  保证数组的完整性
      }
}

3.快速排序

  快速排序从小到大排序:在数组中随机选一个数(默认数组首个元素),数组中小于等于此数的放在左边,大于此数的放在右边,再对数组两边递归调用快速排序,重复这个过程。

 

 

 

void QuickSort(ref List<int> nums, int left, int right)
{
    if (left < right)
    {
        int i = left;
        int j = right;
        int middle = nums[(left + right) / 2];
        while (true)
        {
            while (i < right && nums[i] < middle) { i++; };
            while (j > 0 && nums[j] > middle) { j--; };
            if (i == j) break;
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
            if (nums[i] == nums[j]) j--;
        }
        QuickSort(ref nums, left, i);
        QuickSort(ref nums, i + 1, right);
    }
}

4.插入排序

顺序从数组里取出数据,然后插入到前面有序数组里

private int[] Insertion(int[] list) //插入排序 传入数组 3, 6, 2, 1, 9, 5, 4, 7 
{
    for (int i = 1; i < list.Length; i++)  //首选取出第一个数(3)作为一个有序的数组,然后遍历传入数组"3"之后的每一个数
    {
        int j;
        int key = list[i];
        for (j = i - 1; j >= 0; j--) //因为取出来的数是一个有序数组,排序是从小往大递增的,所以插入新的数字的时候只需要
        {
            if (list[j] < key)       //==>倒序比较,假如比数组的最后一个数字大,前面的就不需要再比较了,这里就是最先比较的
            {
                break;              //最大数就是list[j]
            }
            else
            {
                list[j + 1] = list[j]; //假如待插入数字不比最大的一个数字大,就依次跟前面的数字比较,同时把比较过的数字
            }                          //位置依次右移
        }
        list[j + 1] = key;              //最后找到合适的位置插入数组
    }
    return list;
}

5.希尔排序

对i跟i+gap比较,直至gap==1,比较完成

 public static void ShellSort(int[] array)
 {
     int gap = array.Length / 2;
     while (1 <= gap)
     {
         // 把距离为 gap 的元素编为一个组,扫描所有组
         for (int i = gap; i < array.Length; i++)
         {
             int j = 0;
             int temp = array[i];
             // 对距离为 gap 的元素组进行排序
             for (j = i - gap; j >= 0 && temp < array[j]; j = j - gap)
             {
                 array[j + gap] = array[j];
             }
             array[j + gap] = temp;
          }
          gap = gap / 2; // 减小增量
      }
}

6.归并排序

  将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个有序的子序列,再把有序的子序列合并为整体有序序列。归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法。

public static void MergeSort(int[] inputAray, int first, int end)
        {
            if (first < end)
            {
                int midIndex = (first + end) / 2;
                MergeSort(inputAray, first, midIndex);
                MergeSort(inputAray, midIndex + 1, end);
                MergeMethid(inputAray, first, midIndex, end);
            }
        }

        private static void MergeMethid(int[] inputAray, int first, int midIndex, int end)
        {
            int[] temp = new int[end - first + 1];
            int m = first;
            int n = midIndex + 1;
            int k = 0;
            while (m <= midIndex && n < end)
            {
                if (inputAray[m] < inputAray[n])
                {
                    temp[k] = inputAray[m];
                    k++;
                    m++;
                }
                else
                {
                    temp[k] = inputAray[n];
                    k++;
                    n++;
                }
            }
            while (m <= midIndex)
            {
                temp[k] = inputAray[m];
                k++;
                m++;
            }
            while (n < end)
            {
                temp[k] = inputAray[n];
                k++;
                n++;
            }
            for (k=0,m = first; m < end; k++,m++)
            {
                inputAray[m] = temp[k];
            }

        }

7.堆排序

    public static IList<int> HeapSort(int maxIdx, int[] lst)
    {
        int i = lst.Length - 1;
        int k = 0;

        while (i > -1)
        {
            Swap(maxIdx, i, lst);
            k++;
            //每次缩短无序区最大位置
            maxIdx = GetMax(lst.Length - k, lst);
            i--;
        }

        return lst;
    }
    public static void Swap(int maxIdx, int idx, int[] lst)
    {
        int midx = maxIdx;
        int temp = lst[idx];
        lst[idx] = lst[maxIdx];
        lst[maxIdx] = temp;
    }
    public static int GetMax(int maxLen, int[] lst)
    {
        int maxIdx = 0;
        for (var i = 0; i < maxLen; i++)
        {
            if (lst[i] > lst[maxIdx])
                maxIdx = i;
        }

        return maxIdx;
    }

8.定时器的实现

  update

public float timer = 1.0f; // 定时2秒
void Update() {
    timer -= Time.deltaTime;
    if (timer <= 0) {
        doSomething();
        timer = 2.0f;
    }
}

  monobehavie.invoke

  协程

 

9.二分查找

int binarySearch(int[] nums, int target) {
    int left = 0; 
    int right = nums.length - 1; // 注意

    while(left <= right) { // 注意
        int mid = (right + left) / 2;
        if(nums[mid] == target)
            return mid; 
        else if (nums[mid] < target)
            left = mid + 1; // 注意
        else if (nums[mid] > target)
            right = mid - 1; // 注意
        }
    return -1;
}

10.遍历二叉树

// 二叉树前序遍历   根-> 左-> 右
 public static void preOrderTraveral(TreeNode node)
{
    if(node == null)
    {
        return;
     }
    System.out.print(node.data+" ");
    preOrderTraveral(node.leftChild);
    preOrderTraveral(node.rightChild);
}
//二叉树中序遍历   左-> 根-> 右
public static void inOrderTraveral(TreeNode node)
{
    if (node == null)
    {
        return;
    }
    inOrderTraveral(node.leftChild);
    System.out.print(node.data + " ");
    inOrderTraveral(node.rightChild);
}
// 二叉树后序遍历   左-> 右-> 根
public static void postOrderTraveral(TreeNode node)
{
    if (node == null)
    {
        return;
    }
    postOrderTraveral(node.leftChild);
    postOrderTraveral(node.rightChild);
    System.out.print(node.data + " ");
}
public static void levelOrder(TreeNode root)
{
    LinkedList<TreeNode> queue = new LinkedList<>();
    queue.add(root);
    while (!queue.isEmpty())
    {
        root = queue.pop();
        System.out.print(root.data + " ");
        if (root.leftChild != null) queue.add(root.leftChild);
        if (root.rightChild != null) queue.add(root.rightChild);
    }
}

 11.Dijkstra最短路径算法

//V1到V7的邻接矩阵
    static int[,] Metro = new int[7, 7] {
{ 0, 3, 7, 5,2048,2048,2048},
{ 3, 0, 2,2048, 6,2048,2048},
{ 7, 2, 0, 3, 3,2048,2048},
{ 5,2048, 3, 0,2048, 2, 8},
{2048, 6, 3,2048, 0,2048, 2},
{2048,2048,2048, 2,2048, 0, 2},
{2048,2048,2048, 8, 2, 2, 0}};
    static int row = 7;
    ArrayList S = new ArrayList(row);//S储存确定最短路径的顶点的下标
    ArrayList U = new ArrayList(row);//U中存储尚未确定路径的顶点的下标
    int[] distance = new int[7];//用以每次查询存放数据
    int[] prev = new int[7];//用以存储前一个最近顶点的下标
    bool[] Isfor = new bool[7] { false, false, false, false, false, false, false };
    /// <summary>
    /// dijkstra算法的实现部分
    /// </summary>
    /// <param name="Start"></param>
    void FindWay(int Start)
    {
        S.Add(Start);
        Isfor[Start] = true;
        for (int i = 0; i < row; i++)
        {
            if (i != Start)
                U.Add(i);
        }
        for (int i = 0; i < row; i++)
        {
            distance[i] = Metro[Start, i];
            prev[i] = 0;
        }
        int Count = U.Count;
        while (Count > 0)
        {
            int min_index = (int)U[0];//假设U中第一个数存储的是最小的数的下标
            foreach (int r in U)
            {
                if (distance[r] < distance[min_index] && !Isfor[r])
                    min_index = r;
            }
            S.Add(min_index);//S加入这个最近的点
            Isfor[min_index] = true;
            U.Remove(min_index);//U中移除这个点;
            foreach (int r in U)
            {
                //查找下一行邻接矩阵,如何距离和上一个起点的距离和与数组存储的相比比较小,就更改新的距离和起始点,再比对新的起点到各边的距离
                if (distance[r] > distance[min_index] + Metro[min_index, r])
                {
                    distance[r] = distance[min_index] + Metro[min_index, r];
                    prev[r] = min_index;
                }
                else
                {
                    distance[r] = distance[r];
                }
            }
            Count = U.Count;
        }
    }

 

6. 手撕代码,字符串单词反转 

1、手撕最小子矩阵。 

3、场景题:实现空投点如何在一个圆内均匀且随机。

比如:一个数组,怎么不用循环,不逐一赋值,把它逆序输出。

6. 二维数组, 左上角到右下角 走过的点和最小多少( 矩阵dp)

7. 判断点在三角形

-- 问了下碰撞检测四叉树

2. 手撕十进制反转 123->321 (一开始以为01反转直接返回了 ~num, 面试官:?)

3. 手撕字符串去掉空格,要求用char* 操作( 开了新字符串,实际上可以记空格数遍历时去除,而且面试官说有语法问题)

4. 手撕数组内k高频数据 (先统计频率 map/桶; 然后用小顶堆维护其中k大的频率 复杂度nlogk) 

12. 手撕 双链表反转

2. 游戏内如何判断一个点在空气墙内?(空气墙一般是AABB。 若问是否可达可以用射线判断)

3. 如何判断一个点在多边形内 ? 如何判断一个点在三角形内

6. 快速求中位数

7. 手写链表排序链表几年没操作过了, 凉凉)

两个堆栈实现队列操作

 1.缓存算法

posted @ 2020-10-13 13:04  Elijah_j  阅读(171)  评论(0编辑  收藏  举报