剑指offer--算法类

排序

  • 035-数组中的逆序对(归并排序)
  • 029-最小的K个数(堆排序)
  • 029-最小的K个数(快速排序)

数组中的逆序对

题解

利用「归并排序」计算逆序对,是非常经典的做法

最小的K个数

题解

/*
在面试中,另一个常常问的问题就是这两种方法有何优劣.看
 * 起来分治法的快速选择算法的时间、空间复杂度都优于使用堆的方法,
 * 但是要注意到  快速选择算法的几点局限性:
 *
 * 第一,算法需要修改原数组,如果原数组不能修改的话,还需要拷贝一份数组,空间复杂度就上去了
 *
 * 第二,算法需要保存所有的数据。如果把数据看成输入流的话,
 * 使用堆的方法是来一个处理一个,不需要保存数据,只需要保存 k 个元素的最大堆。
 * 而快速选择的方法需要先保存下来所有的数据,再运行算法。
 * 当数据量非常大的时候,甚至内存都放不下的时候,就麻烦了。
 * 所以当数据量大的时候还是用基于堆的方法比较好。
*/
public class 最小的K个数 {
    /**
     * 由于使用了一个大小为 k 的堆,空间复杂度为 O(k);
     *  * 入堆和出堆操作的时间复杂度均为 O(logk)
     *  * 每个元素都需要进行一次入堆操作,故算法的时间复杂度为 O(nlogk)
     * @param input
     * @param k
     * @return
     */
    //尺寸为K的 大顶堆
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {

        ArrayList<Integer> list=new ArrayList<>();
        if(input==null||input.length==0||k==0||k>input.length) return list;
        //构建大顶堆
        Queue<Integer> heap=new PriorityQueue<>(k,(v1, v2)->Integer.compare(v2,v1));

        for(int e:input){
            if(heap.isEmpty()||heap.size()<k||e<heap.peek()){
                heap.offer(e);
            }
            if(heap.size()>k){
                heap.poll();//弹出最大的 堆顶元素
            }
        }
        list.addAll(heap);
        return list;
//        return (ArrayList<Integer>) heap;错误

//        for (int i = 0; i < k; i++) {
//            list.addAll()
//        }



    }

    /**
     * 空间复杂度 O(1),不需要额外空间。递归 辅助栈
     * 时间复杂度的分析方法和快速排序类似。
     * 由于快速选择只需要递归一边的数组,时间复杂度小于快速排序,
     * 期望时间复杂度为 O(n),最坏情况下的时间复杂度为 O(n^2)。
     *
     * 作者:nettee
     * 链接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/solution/tu-jie-top-k-wen-ti-de-liang-chong-jie-fa-you-lie-/
     * 来源:力扣(LeetCode)
     * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
     * @param arr
     * @param k
     * @return
     */
    public int[] getLeastNumbers(int[] arr, int k) {
//        ArrayList
        if(k==0) return new int[0];
        if(arr==null||arr.length<=k) return arr;

        select(arr,0,arr.length-1,k);
        int[] res=new int[k];
        // int[] res=Arrays.copyOf(arr,k);
        for(int i=0;i<k;i++){
            res[i]=arr[i];
        }
        return res;
    }

    public void select(int[] nums, int low, int high,int k){
        int pivot=partiton(nums,low,high);
        if(pivot==k) return;
        else if(pivot>k){
            select(nums,low,pivot-1,k);
        }else{
            //我们在右侧数组中寻找最小的 k-m 个数,
            // 但是对于整个数组而言,这是最小的 k 个数。所以说,函数调用传入的参数应该为 k。
            select(nums,pivot+1,high,k);
        }
    }

    public int partiton(int[] nums, int low, int high) {
        int key=nums[low];
        int i=low,j=high+1;
        while(true){
            while((nums[++i]<key)&&i<high);
            while((key<nums[--j])&&j>low);
            //退出循环条件
            if(i>=j) break;
            swap(nums,i,j);

        }
        swap(nums,j,low);
        return j;
    }

    public void swap(int[] nums,int i,int j){
        int tmp=nums[i];
        nums[i]=nums[j];
        nums[j]=tmp;
    }

}

位运算

  • 011-二进制中1的个数
  • 012-数值的整数次方
  • 040-数组中只出现一次的数字

二进制中1的个数

题解

public class Solution {
    public int NumberOf1(int n) {
        int sum=0;
        while(n!=0){
            if((n&1)!=0){
                sum++;
            }
            n=n>>>1;//无符号右移,补0
        }
        return sum;
    }
}
public class Solution {
    public int hammingWeight(int n) {
        int res = 0;
        while(n != 0) {
            res++;
            n &= n - 1;
        }
        return res;
    }
}

数值的整数次方

快速幂

class Solution {
    public double myPow(double x, int n) {
        if(x==0) return 0;
        double res=1.0;
        long b=n;
        if(b<0){
            b=-b;
            x=1/x;
        }
        while(b>0){
            if((b&1)==1) res*=x;
            x*=x;
            b>>=1;
        }
        return res;
        
  }
}

数组中只出现一次的数字||第一个只出现一次的字符

相反数互与 最低位1
在这里插入图片描述

class Solution {
    public int[] singleNumbers(int[] nums) { 
        int num=0;
        int a=0,b=0;
        for(int n:nums){
            num^=n;
        }
        //找num最低位1
        int mask=num&(-num);
        for(int n:nums){
            if((n&mask)==0){
                a^=n;
            }else{
                b^=n;
            }
        }
        return new int[]{a,b};

    }
}
class Solution {
    public char firstUniqChar(String s) {
        HashMap<Character,Integer> map=new HashMap<>();
        char[] arr=s.toCharArray();
        for(int i=0;i<arr.length;i++){
            if(map.containsKey(arr[i])){
                map.put(arr[i],map.get(arr[i])+1);
            }
            else{
                map.put(arr[i],1);
            }
        }
//        for(Map.Entry<Character,Integer> t:map.entrySet()){
//            char m= (char) t.getKey();
//            int n= (int) t.getValue();
//            if(n==1) return m;
//        }
        for(char c:arr){
            if(map.get(c)==1) return c;
        }
        return ' ';
    
    
    }
}

搜索算法

001-二维数组查找
006-旋转数组的最小数字(二分查找)
037-数字在排序数组中出现的次数(二分查找)

二维数组查找

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        if(matrix==null||matrix.length==0||matrix[0].length==0){
            return false;
        }
        int rows=matrix.length,cols=matrix[0].length;
        int i=0,j=cols-1;
        while(i<rows&&j>=0){
            if(matrix[i][j]==target){
                return true;
            }else if(matrix[i][j]<target){
                i++;
            }else{
                j--;
            }
        }
        return false;
    }
}

旋转数组的最小数字

二分查找

class Solution {
    public int minArray(int[] numbers) {
        int i=0,j=numbers.length-1;
        while(i<j){
            int m=(i+j)/2;
            if(numbers[m]>numbers[j]) i=m+1;
            else if(numbers[m]<numbers[j]) j=m;
            else j--;
        }
        return numbers[i];

    }
}

数字在排序数组中出现的次数

排序数组中的搜索问题,首先想到 二分法 解决。

二分查找

class Solution {
    public int search(int[] nums, int target) {

        // 搜索右边界 right
        int i = 0, j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] <= target) i = m + 1;
            else j = m - 1;
        }
        int right = i;
        // 若数组中无 target ,则提前返回
        if(j >= 0 && nums[j] != target) return 0;
        // 搜索左边界 right
        i = 0; j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] < target) i = m + 1;
            else j = m - 1;
        }
        int left = j;
        return right - left - 1;


    }
}

类似
34. 在排序数组中查找元素的第一个和最后一个位置

全排列

027-字符串的排列

字符串的排列

排列组合问题,一般是回溯法解
回溯法

在这里插入图片描述

class StringRank {
    private ArrayList<String> res = new ArrayList<>();
    private TreeSet<String> paths = new TreeSet<>();
    private StringBuilder path = new StringBuilder();
    private boolean[] visited;
 
    public ArrayList<String> Permutation(String str) {
        if (str == null || str.equals("")) {
            return res;
        }
        char[] strs = str.toCharArray();
        Arrays.sort(strs);
        visited = new boolean[strs.length];
        combination(strs, 0);
        res.addAll(paths);
        return res;
    }
 
    private void combination(char[] strs, int len) {
        if (len == strs.length) {
            paths.add(path.toString());
            return;
        }
        for (int i = 0; i < strs.length; i++) {
            if (!visited[i]) {
                visited[i] = true;
                path.append(strs[i]);
                combination(strs, len + 1);
                //Duang ~ 回溯 - 状态重置
                visited[i] = false;
                path.deleteCharAt(path.length() - 1);
            }
        }
    }
}

在这里插入图片描述在这里插入图片描述

在这里插入图片描述会有问题:abc 虽然力扣通过了,但是剑指不通过
输出[abc, acb, bac, bca, cba, cab]
最后两个顺序有错误

class Solution {
    char[] c;
    List<String> list=new LinkedList<>();
    public String[] permutation(String s) {
        c=s.toCharArray();
        dfs(0);
        //添加排序
        Collections.sort(list);
        return list.toArray(new String[list.size()]);
    }

    public void dfs(int pos){
        if(pos==c.length-1){
            list.add(String.valueOf(c));
            return;
        }
        HashSet<Character> set=new HashSet<>();
        for(int i=pos;i<c.length;i++){
            if(set.contains(c[i])) continue;
            set.add(c[i]);
            swap(i,pos);
            //递归下一层
            dfs(pos+1);
            //回溯
            swap(i,pos);
        }
    }

    public void swap(int i,int j){
        char tmp=c[i];
        c[i]=c[j];
        c[j]=tmp;
    }
}

全排列1

全排列2

动态规划

030-连续子数组的最大和
052-正则表达式匹配

连续子数组的最大和

class Solution {
    public int maxSubArray(int[] nums) {


        //不改变原数组
        int max=nums[0],cur=nums[0],pre=0;//pre为dp[-1]
        for(int i:nums){
            if(pre>=0) i+=pre;
            pre=i;

           
            max=Math.max(max,i);
        }
        return max;
        // //动态规划
        // //dp[i]以nums[i]为结尾的连续数组和
        // //dp[i]=dp[i-1](>0)+nums[i]
        // int max=nums[0];
        // for(int i=1;i<nums.length;i++){
        //     nums[i]+=Math.max(nums[i-1],0);
        //     max=Math.max(max,nums[i]);
        // }
        // return max;


    }
}

正则表达式匹配

动态规划

图解

以一个例子详解动态规划转移方程:
S = abbbbc
P = ab*d*c
1. 当 i, j 指向的字符均为字母(或 '.' 可以看成一个特殊的字母)时,
   只需判断对应位置的字符即可,
   若相等,只需判断 i,j 之前的字符串是否匹配即可,转化为子问题 f[i-1][j-1].
   若不等,则当前的 i,j 肯定不能匹配,为 false.
   
       f[i-1][j-1]   i
            |        |
   S [a  b  b  b  b][c] 
   
   P [a  b  *  d  *][c]
                     |
                     j
   

2. 如果当前 j 指向的字符为 '*',则不妨把类似 'a*', 'b*' 等的当成整体看待。
   看下面的例子

            i
            |
   S  a  b [b] b  b  c  
   
   P  a [b  *] d  *  c
            |
            j
   
   注意到当 'b*' 匹配完 'b' 之后,它仍然可以继续发挥作用。
   因此可以只把 i 前移一位,而不丢弃 'b*', 转化为子问题 f[i-1][j]:
   
         i
         | <--
   S  a [b] b  b  b  c  
   
   P  a [b  *] d  *  c
            |
            j
   
   另外,也可以选择让 'b*' 不再进行匹配,把 'b*' 丢弃。
   转化为子问题 f[i][j-2]:

            i
            |
   S  a  b [b] b  b  c  
    
   P [a] b  *  d  *  c
      |
      j <--

3. 冗余的状态转移不会影响答案,
   因为当 j 指向 'b*' 中的 'b', 这个状态对于答案是没有用的,
   原因参见评论区 稳中求胜 的解释, 当 j 指向 '*',
   dp[i][j]只与dp[i][j-2]有关, 跳过了 dp[i][j-1].


class Solution {
    public boolean isMatch(String s, String p) {
        int m=s.length(),n=p.length();
        boolean[][] dp=new boolean[m+1][n+1];

        dp[0][0]=true;
        for(int i=0;i<=m;i++){
            for(int j=1;j<=n;j++){
                if('*'==(p.charAt(j-1))){
                    dp[i][j]=dp[i][j-2];
                    if(matches(s,p,i,j-1)){
                        dp[i][j]=dp[i][j]||dp[i-1][j];
                    }

                }else{
                    if(matches(s,p,i,j)){
                        dp[i][j]=dp[i-1][j-1];
                    }
                }
            }
        }
        return dp[m][n];
    }

    public boolean matches(String s,String p, int i,int j){
        if(i==0){
            return false;
        }
        if(p.charAt(j-1)=='.'){
            return true;
        }
        return p.charAt(j-1)==s.charAt(i-1);

    }
}

排序

035-数组中的逆序对(归并排序)
029-最小的K个数(堆排序)
029-最小的K个数(快速排序)

数组中的逆序对

暴力法会超时

归并排序法

方法栈+按DFS顺序访问

class Solution {
    public int reversePairs(int[] nums) {
        int len = nums.length;
        if(len < 2) return 0;
        int[] copy = new int[len];//避免修改原数组
        for(int i = 0; i < len; i++) copy[i] = nums[i];
        int[] tmp = new int[len];//辅助数组,用于归并两个有序数组
        return reversePairs(copy, 0, len - 1, tmp); //方法重载机制 递归方法 左闭右闭区间
    }
/**
     * nums[left..right] 计算逆序对个数并且排序
     *
     * @param nums
     * @param left
     * @param right
     * @param temp
     * @return
     */

    private int reversePairs(int[] nums, int left, int right, int[] tmp){
        if(left == right) return 0; //递归终结者 只剩下一个元素 不含逆序对
        int mid = left + (right - left) / 2;//此处采用此方式是因为(right + left) / 2中的right + left可能产生越界
        int leftPairs = reversePairs(nums, left, mid, tmp);
        int rightPairs = reversePairs(nums, mid + 1, right, tmp);
		//优化步骤
		//合并两个有序数组之前,如果能检测出 数组已经是有序的
		//则不需要合并,直接将左右边的逆序对的个数
        if(nums[mid] <= nums[mid + 1]) return leftPairs + rightPairs; // 此时,左边子数组的最大数小于右边子数组的最小数,直接合并即可,不会产生逆序对
        int crossPairs = mergerAndCount(nums, left, mid, right, tmp); //crossPairs是将两个有序子数组归并为一个有序数组产生的逆序对
        return crossPairs + rightPairs + leftPairs; 
    }
	//nums[left..mid] 有序,nums[mid + 1..right] 有序
    private int mergerAndCount(int[] nums, int left, int mid, int right, int[] tmp){
        //全程采用一个数组tmp的原因有二:不必一直创建新的数组,节约资源;每次处理的都是子数组,如果创建新的数组会导致索引的处理很麻烦,容易出错
        for(int i = left; i <= right; i++) tmp[i] = nums[i];
        int i = left;   //左边的有序数组的左边界
        int j = mid + 1;//右边的有序数组的左边界
        int count = 0;//计数器
        for(int k = left; k <= right; k++){
            if(i == mid + 1){//i到边界,只能将j归并回去
                nums[k] = tmp[j]; //此时左边的子数组长度为0
                j++;
            }else if(j == right + 1){
                nums[k] = tmp[i]; //此时右边的子数组长度为0
                i++;
			//i,j均在有效位置
            }else if(tmp[i] <= tmp[j]){ //这儿必须得是“<=”,如是“<”,则归并排序是不稳定的
                nums[k] = tmp[i]; //左边子数组的值较小,进入有序数组
                i++;
            }else{
                nums[k] = tmp[j]; //此时,右边子数组的值较小,进入有序数组
                j++;
                count += (mid - i + 1);//左边子数组剩余的个数即为逆序对个数
            }
        }
        return count;
    }
}
import java.io.*;
public class Main {
    public static int InversePairs(int [] array) {
        if(array == null) return 0;
        int[] tmp = new int[array.length];
        return mergeSort(array, tmp, 0, array.length-1);
    }
 
    //归并排序,递归
    private static int mergeSort(int[] array, int[] tmp, int low, int high) {
        if(low >= high) return 0;
        int res = 0, mid = low + (high - low) / 2;
        res += mergeSort(array, tmp, low, mid);
        res %= 1000000007;
        res += mergeSort(array, tmp, mid + 1, high);
        res %= 1000000007;
        res += merge(array, tmp, low, mid, high);
        res %= 1000000007;
        return res;
    }
 
    //归并排序,合并
    private static int merge(int[] array, int[] tmp, int low, int mid, int high) {
        int i = low, i1 = low, i2 = mid + 1;
        int res = 0;
        while(i1 <= mid && i2 <= high) {
            if(array[i1] > array[i2]) {
                res += mid - i1 + 1;
                res %= 1000000007;
                tmp[i++] = array[i2++];
            } else
                tmp[i++] = array[i1++];
        }
        while(i1 <= mid)
            tmp[i++] = array[i1++];
        while(i2 <= high)
            tmp[i++] = array[i2++];
        for (i = low; i <= high; i++)
            array[i] = tmp[i];
        return res;
    }
     
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str = br.readLine();
        str = str.substring(1, str.length()-1);
        String[] valueArr = str.split(",");
        int[] array = new int[valueArr.length];
        for (int i = 0; i < valueArr.length; i++) {
            array[i] = Integer.parseInt(valueArr[i]);
        }
         
        System.out.println(InversePairs(array));
    }
}

图解

视频解(推荐)

88. 合并两个有序数组

327.区间和的个数

315. 计算右侧小于当前元素的个数

最小的K个数

import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.Queue;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> list=new ArrayList<>();
        if(input==null||input.length==0||k==0||k>input.length) return list;
        //构建大顶堆
        Queue<Integer> heap=new PriorityQueue<>(k,(v1, v2)->Integer.compare(v2,v1));
        for(int e:input){
            if(heap.isEmpty()||heap.size()<k||e<heap.peek()){
                heap.offer(e);
            }
            if(heap.size()>k){
                heap.poll();
            }
        }
        list.addAll(heap);
        return list;
        //wrong return (ArrayList<Integer>) heap;
    }
}

其他

002-替换空格
013-调整数组顺序使奇数位于偶数前面
028-数组中出现次数超过一半的数字
031-整数中1出现的次数(从1到n整数中1出现的次数)
032-把数组排成最小的数
033-丑数
041-和为S的连续正数序列(滑动窗口思想)
042-和为S的两个数字(双指针思想)
043-左旋转字符串(矩阵翻转)
046-孩子们的游戏-圆圈中最后剩下的数(约瑟夫环)
051-构建乘积数组

替换空格

public class Solution {
    public String replaceSpace(StringBuffer str) {
        int p1=str.length()-1;
        for(int i=0;i<=p1;i++){
            char c=str.charAt(i);
            if(c==' ')
                str.append("  ");
        }
        int p2=str.length()-1;
        while(p2>p1&&p1>=0){
            char c=str.charAt(p1--);
            if(c==' '){
                str.setCharAt(p2--,'0');
                str.setCharAt(p2--,'2');
                str.setCharAt(p2--,'%');
            }else{
                str.setCharAt(p2--,c);
            }
        }
        return str.toString();
         
    }
}

调整数组顺序使奇数位于偶数前面

双指针

在这里插入图片描述

第一反应用辅助list,但空间复杂度上去了

import java.util.*;
public class Solution {
    public void reOrderArray(int [] array) {
        if(array==null)  return;
        List<Integer> odd=new ArrayList<>();
        List<Integer> even=new ArrayList<>();
        int len=array.length;
        for(int i=0;i<len;i++){
            if(array[i]%2==0){
                even.add(array[i]);
            }else{
                odd.add(array[i]);
            }
        }
        
        //int[] res=new int[len];
        for(int i=0;i<len;i++){
            if(i<odd.size()){
                array[i]=odd.get(i);
            }else{
                array[i]=even.get(i-odd.size());
            }
        }
        
    }
}

数组中出现次数超过一半的数字

在这里插入图片描述

class Solution {
    public int majorityElement(int[] nums) {
        int x = 0, votes = 0, count = 0;
        for(int num : nums){
            if(votes == 0) x = num;
            votes += num == x ? 1 : -1;
        }
        // 验证 x 是否为众数
        for(int num : nums)
            if(num == x) count++;
        return count > nums.length / 2 ? x : 0; // 当无众数时返回 0
    }
}

作者:jyd
链接:https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/solution/mian-shi-ti-39-shu-zu-zhong-chu-xian-ci-shu-chao-3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1~n 整数中 1 出现的次数

数学法

递归
在这里插入图片描述

丑数

动态规划

public class Solution {
    public int GetUglyNumber_Solution(int index) {
        if(index==0) return 0;
        int[] dp=new int[index];
        dp[0]=1;
        int p2=0,p3=0,p5=0;
        for(int i=1;i<index;i++){
            dp[i]=Math.min(Math.min(dp[p2]*2,dp[p3]*3),dp[p5]*5);
            if(dp[i]==dp[p2]*2){
                p2++;
            }
            if(dp[i]==dp[p3]*3){
                p3++;
            }
            if(dp[i]==dp[p5]*5){
                p5++;
            }
        }
        
        return dp[index-1];
    }
}

扑克牌顺子

import java.util.HashSet;
public class Solution {
    public boolean isContinuous(int [] numbers) {
        if(numbers==null||numbers.length==0) return false;
        int max=0,min=14;
        HashSet<Integer> set=new HashSet<>();
        for(int i=0;i<numbers.length;i++){
            if(numbers[i] == 0) continue; // 跳过大小王
            min=Math.min(min,numbers[i]);
            max=Math.max(max,numbers[i]);
            if(set.contains(numbers[i]))
            {
                return false;
            }
            set.add(numbers[i]);
        }
        return max-min<5;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
经导师精心导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值