刷题注意事项

注意点

  1. 判断数据的大小,然后决定使用正常题解或者其他方式当参数为对象时,需要先判断参数是否为空;
  2. 对于给定的参数,考虑参数最小时的情况,如长度为1或者0
  3. 使用到节点属性前,先判断节点是否为空;
  4. 在循环中使用if分支,要考虑分支体内是否跳出本次循环
  5. 使用循环时,要考虑循环的终止条件,当利用循环从集合中取出特定元素时,取值操作要在循环体内和循环体外定义两次,保证判断条件的不断更新;
  6. 使用循环时,要特别注意循环的终止条件
  7. 当对一个字符串进行倍数复制时,要额外定义一个临时变量存储当前值,然后再对当前对象执行自增操作,因为每次操作,当前变量都在变化,不能str=+str;
  8. 倍数复制时,当前已占据一;
  9. 需要对固定结构的序列做增删操作时,可以定义一额外的动态结构来保存中间结果,不直接在元结构上改变
  10. 对某一序列执行相同的操作,可以将该序列定义为数组
  11. 在循环中(i自增判断),结束条件不能使用动态链表或者栈的大小,因为在循环体内更改链表的大小,会造成循环条件的动态改变
  12. 仅对相邻的两个元素进行操作,可以考虑使用栈结构,取出数据后,要注意数据的再次保存
  13. 需要使用字典序时,可以将两字符串拼接完成后,用compareTo方法进行比较
  14. 循环条件中只使用范围,不使用具体指(存在击穿)
  15. 集合中可以存储空值,并且该空值可以被取出

基础

  1. 二叉树的层次遍历
    1. 使用队列存储层层次上的节点,然后取出遍历,循环,条件为队列非空,提前将根节点加入队列中
    2. 使用两个队列,额外队列中仅存储当前层次的节点,当主队列为空时,将层次队列中的值添加到主队列
    3. 针对每一层,可以在取数前计算其节点数count,然后取出count个数,进行下一层次遍历,可以单独得到每一层次的节点
  Queue<TreeNode> q=new ArrayDeque();
        q.add(root);
        while (!q.isEmpty()){
        //count计数,仅记录当前层次
            int count=q.size();
            List<Integer> item=new LinkedList<>();
            while(count>0){
                TreeNode treeNode=q.poll();
                item.add(treeNode.val);
                if(treeNode.left!=null){
                    q.add(treeNode.left);
                }
                if(treeNode.right!=null){
                    q.add(treeNode.right);
                }
            count--;    
            }
            res.add(item);
        }
        return res;
  1. 使用队列模拟栈
    1. 使用两个队列,都用于存值,其中必有一个保持为空
    2. 将数据插入空的队列中,然后将另一个存有数据的队列值取出,存入该队列,此时,另一队列为空,本队列非空(每插入一个数据,就要执行一次反转操作,如3个数据,要反转好多次)
    3. 取值时,从存有值得队列中直接取值即可
    4. 插入比较耗时
  2. 使用栈来模拟队列
    1. 使用两个栈来模拟队列,一个栈作为输入,另一个栈作为输出
    2. 存数据时存入输入栈,
    3. 取数据值从输出栈取数据,当输出栈为空时,将输入栈中所有元素存入输出栈,再进 行取值操作
  3. 二叉树的遍历,迭代,递归实现
    递归
    1. 以根节点为参数,返回值为空
    2. 当根非空时,以左右节点为根节点进行分解
    3. 左右节点递归顺序以及根节点值读取顺序以遍历方式来决定
   public void pre(TreeNode root) {
        if(root==null){
            return;
        }
        //其位置决定其为前序,中序或后序
        System.out.println(root.val);
        pre(root.left);
        pre(root.right);
        
    }
迭代1(改变原结构)
  1. (后序)使用栈来存储节点,先存根节点,循环,栈非空
  2. 存储左右节点时,保存一份左右节点的值,然后再栈中现存右节点,再存左节点,存储后,断开与根节点的联系
  3. 判断节点左右都为空时,取出存储值,(会按照左,右,根的顺序执行)
public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if (root == null) {
            return list;
        }
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode r = stack.peek();
            TreeNode left=r.left;
            TreeNode right= r.right;
            if (r.right != null) {
                stack.push(r.right);
                r.right=null;
            }
            if (r.left != null) {
                stack.push(r.left);
                r.left=null;
            }
            if(left==null&&right==null){

                list.add(stack.pop().val);
            }
        }
        return list;
    }
迭代2(不改变原结构)
  1. 以左节点,不断遍历,直至左节点为空,此时,回退到父节点(回退后不能再重新遍历左节点),先左后右
  2. 左节点为空后,若右节点非空,则存入右节点,重新循环;否则,取出当前节点值,并从栈中弹出,回退到上一节点
  3. 回退到上一节点后,需要判断其左右子树是否都遍历过了,加上上一判断条件,故记录上一次被弹出节点,作为判断右子树是否被访问依据;对于左子树,在遍历至空后,该变当前值为null,对右子树判断前,再次从栈中取值(左子树循环的条件中,值不能直接从栈中取值,使用其他变量)
public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if (root == null) {
            return list;
        }
        stack.push(root);
        TreeNode l=stack.peek().left;
        TreeNode last=null;
        TreeNode r=null;
        while (!stack.isEmpty()) {
            while(l!=null){
                stack.push(l);
                l=stack.peek().left;
            }
            r=stack.peek();
            if(r.right!=null&&r.right!=last){
                stack.push(r.right);
                 l=stack.peek().left;
            }else{
                TreeNode c=stack.pop();
                list.add(c.val);
                l=null;
                last=c;
            }
        }
        return list;
    }
迭代3(使用前序)
  1. 前序迭代中,每次存储根节点的值(先存右节点,再存左节点),每次取值时,为从栈弹出的根节点,为根左右,
  2. 改变前序存储顺序,先存左,再存右,则下次循环取出节点为右节点,序列变为根右左,将结果序列反转,则变为后序
//前序遍历
public List<Integer> preorderTraversal(TreeNode root) {
        if (root == null) {
            return null;
        }
        List<Integer> list = new ArrayList<Integer>();
        Stack<TreeNode> s = new Stack<TreeNode>();
        s.push(root);

        while (!s.isEmpty()) {
            TreeNode node = s.pop();
            list.add(node.val);
            if (node.right != null) {
                s.push(node.right);
            }
            if (node.left != null) {
                s.push(node.left);
            }
        }
        return list;
    }
  1. 根据前序,中序构造二叉树
    1. 使用链表重新封装中序数组,或使用开始和结束下标的方式
    2. 还可以使用map封装中序队列,提高查询速度
    3. 以前序数组中元素为根节点,分割中序数组为左右部分,然后进行递归操作,递归返回分界点
    4. 将左右子树看成一个单独的树来处理,递归的终结位置为链表长度为1或者为null,直接构造该节点对象,然后返回
    5. 根据前序顺序,先处理左树,再处理右树,划分的左右子树中,不要包括根节点,故右子树的划分初始值要index位置加1;
    6. 参数中传入前序数组以及相应的下标,处理左子树时,下标为参数中的根下标+1,右子树传入根下标为根下标+中序左链表的长度+1;
    7. 可以根据以根节点分割的中序左右子树的链表得到左右子树的长度
 public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
        List<Integer> li = new ArrayList<>(in.length);
        for (int i : in) {
            li.add(i);
        }
        return help(pre, 0, li);
    }

    public static TreeNode help(int[] pre, int i, List<Integer> li) {
        if (li == null || li.size() == 0) {
            return null;
        }
        if (li.size() == 1) {
            return new TreeNode(li.get(0));
        }
        List<Integer> left = li.subList(0, li.indexOf(pre[i]));
        List<Integer> right = li.subList(li.indexOf(pre[i])+1, li.size());
        TreeNode root = new TreeNode(pre[i]);
        root.left = help(pre, i +1, left);
        root.right = help(pre, i + left.size() + 1, right);
        return root;
    }
  1. 根据中序和后序构造二叉树
    1. 处理时,与上相反,先处理右树,再处理左树
    2. 以后序序列为主,反向进行,,末尾为根元素
    3. 左树下标为 根-右树长度-1
public TreeNode buildTree( int[] inorder,int[] preorder) {
        if (preorder.length == 0)
            return null;
        List<Integer> li = new ArrayList<>(inorder.length);
        for (int i : inorder)
            li.add(i);
        return buildTree(preorder.length-1, li, preorder);

    }

    public TreeNode buildTree(int r, List<Integer> order, int[] post ) {
        if (r <0)
            return null;
        int rootIndex = order.indexOf(post[r]);
        if (rootIndex == -1) {
            return null;
        }
        TreeNode root = new TreeNode(post[r]);
        List<Integer> left = order.subList(0, rootIndex);
        List<Integer> right = order.subList(rootIndex + 1, order.size());
        root.right = buildTree(r-1, right, post);
        root.left= buildTree(r - right.size()-1, left, post);
        return root;

    }
  1. hashset,treeset的实现以及原理
  2. 红黑树在map中的使用

技巧

集合操作
  1. list.remove()方法直接传入数字,会按照删除下标的方式来删除,传入(integer)2时,会按照删除对象的方式来删除
  2. int[]类型的数组不能直接转换成list,只有引用类型的数组可以转换为list
  3. list.subList()并不生成新的链表,引用的仍为原对象,且增改均会反映到源对象上
排序
  1. 排序中,比较器可以使用方法体中的其他对象,并非一定在列表中的对象
  2. 键值对的排序,可以在比较器中引用该map,如PriorityQueue<Integer> heap = new PriorityQueue<Integer>((n1, n2) -> count.get(n1) - count.get(n2));,count为map,往heap存值时,仅存其key即可
排列组合
  1. 可以使用01二进制位数来表示序列中数据的排列组合,1左移n位表示n个数的排列,0~ n 中每一个数右移0~ n次,判断对应的每一位数是否应该存在
  2. 1<<n(n+1位)表示n个数据的排列,其中,包含空(0),在0~n的数值中,n值不可达,表示n位数据的排列组合,最大值为n位全1
  3. 判断相应位上是否为1,使用右移位,与1相与(i>>j)&1,j为位数,判断第1位(从一开始)时,j应该为0,故j的范围也是0~n,n不可达
  4. 也可以使用回溯法求解
位运算
  1. ^异或,相同位0,不同为1,一个数,和其本身异或的结果为0,与0异或的结果为其本身
  2. 异或可以用来求解多对重复值中仅有一个不同的情况
  3. |按位或,只要有一个为1,则为1,可以用来设定某个数的某一位为1;
  4. &按位与,两个都为1,结果才为1,可以用来取某些特定位上的值,比如设定本身某些位为1,然后与其他数按位与,得到另一个数对应二进制位上的值
  5. ~取反,a & (-a),可以得到a的最低非零位,负数是将证书取反加一,结果中,除a最低非零以外,其余都为0
  6. 左移相当于乘以2,右移相当于除2(奇数为减一除2)
  7. 判断对应的j位是否为1int b = 1 << j; int c = i & b;
  8. 使j位为0int s2 = ~(1 <<j);s2 = i & s2;
  9. 判断字符串是否包含另一个字符串时(多次不通知判断),可以将字符串转换为相应的位数,然后,进行按位与操作,若不包含,则值为零(转换时要注意相同字母重复添加)
  10. 给数据添加不同位时,可使用按位或运算,可以避免相同为上的重复添加
  11. 可以按位与判断不同位上的值,但相应的判断结果也应该是 2 n 2^n 2n,并非总是为1
  12. int位运算时,可以转换为long ,防止溢出
  13. 存储
特性数
  1. 众数是出现次数1/2频度以上,那么若现将数组排序,中位数必为众数!
  2. 一个数+1时,总会有这么一个规律“某一位后的数字,全部被置为相反数”,故某个范围内的每个数按位与时,只需要求出开始值与结束值得相同前缀,若不存在,则为0
  3. 对于其他数重复,仅有两个不重复的数,先使其异或,得到结果中必定某一位为一,使用x=a & (-a)得到异或结果中含一的最低为,根据该位,将原数组分为两部分,则每一部分中为仅含一个不同项,其他都是重复项,(对于重复项,在该位上,要么都为1,要么都为0)通过按位与结果是否为得到的仅含一的值相同(nums[i] & x) == x来划分数组,

题型

二叉树
  1. 前序验证二叉树,其中空节点为叶子节点
    解: 使用栈保存节点,利用栈的回退特性,遇到要空节点时,判断站定是否为空,若为空,则将栈顶两元素弹出,并存入# 代替,若不为空,则存入(此时不可判断最终结果);进行下一次判断;至所有结果遍历完成,最终结果中,若仅剩余一个#,则正确;依次剪短二叉树的分支,并使用空来代替该分支
前n个某种特性的数据序列
  1. 如求前n个质数等,将其置于堆中,使其自然排序,而后,取出堆顶最小值,根据某种特性再进行拓展;使用堆得每次插入和弹出都会再次排序的特性,快速构造出某序列,且其经过排序,但是,插入时,要考虑生成值得重复问题,且已插入堆中的值,即使未使用,也不可丢弃,否则,会使数据不完整
  2. 根据primes列表生成新的数据
  3. 可以使用多指针,记录结果数据,使primes中的每一项在相乘时对应结果数据中的不同项,如primes为2,3,5;初始为1,则primes中每一项对应结果中的第一项,而后,值2对应的索引加一,另外两个不变
  4. 在生成数据时,存在重复计算,每次生成固定长度的结果集(primes的长度),从中取最小值,取出最小值后,判断最小值对应primes中的哪一项,对应项在res中的索引加一
  5. 当生成的数据中存在重复值时,则重复值对应的结果索引都加一
  6. 使用多指针,而后合并序列,得到最优结果,手动处理排序结果而非利用堆来处理
分割连续值
  1. (659)判断连续值时,需要考虑存在数组中存在重复值,使用hashmap保存重复值map,而后,根据该map作为判断
  2. 遍历原数组,因为其中有重复项,遍历过程中即可判断能否可行,根据map中的value判断该值是否已经被完全使用,构造endmap,存放序列的末尾,因为重复项,所以相同的序列可能有多个
  3. 遍历时。先判断是否已经被使用完毕,通过map判断,而后,判断能否追加到之前的序列中,需要更改endmap,最后,判断能否生成新的序列,查找并更改map即可,在此步骤中,若map值为0,则移除该键;若都不可行,则不能生成连续序列
序列中仅一个不存在

1.若重复项为2,则使用异或,得到唯一不同项
2. (137)若为多个重复项,则定义32位数组,存储每个数每一位相加的结果,然后对每位判断能否被整除

第k大数
  1. 使用堆维护前k大的数,遍历完成后弹出
n数和问题
  1. (两数和)多次遍历,取值
  2. 使用map结构,遍历一次,另一个值从map 中直接寻找
  3. (三数和)三重嵌套遍历
  4. 两重遍历,最后一层同过map来查找
  5. 排序,一层遍历,后两个数从数组左右依次增减判断( o ( n 2 ) o(n^2) o(n2)
    1. 当需要去除重复时,注意,i位置与i+1相同时,略过i+1位置因为i+1匹配的项必定在Ide结果中存在
    2. 当j和k有重复时,直接略过某一个相同元素即可;但要注意其范围仅为i–n,并非从零开始,否则,会有重复;同时,需要注意全部都为零的情况,故是j不在i+1位置时,开始与之前比较,k不在末尾位置时,与之后比较
    3. for循环中,continue操作不需要i++;
    4. while循环中,使用if分支时要注意结束条件
 public List<List<Integer>> threeSum(int[] nums) {
        
        List<List<Integer>> res = new LinkedList<>();

        Arrays.sort(nums);
        for (int i = 0; i < nums.length - 2; i++) {
        //i位置去重
            if(i!=0&&nums[i]==nums[i-1]){
                continue;
            }
            int j = i + 1;
            int k = nums.length - 1;
            while (j < k) {
            // //j,k位置去重
                if (j!=i+1&&nums[j] == nums[j - 1]) {
                    j++;
                    continue;
                }
                if(k!=nums.length-1&&nums[k]==nums[k+1]){
                    k--;
                    continue;
                }
                if (nums[j] + nums[k] > -nums[i]) {
                    k--;
                } else if (nums[j] + nums[k] < -nums[i]) {
                    j++;
                } else if (nums[j] + nums[k] == -nums[i]) {
                    List<Integer> li = new ArrayList<>(3);
                    li.add(nums[i]);
                    li.add(nums[j]);
                    li.add(nums[k]);
                    j++;
                    res.add(li);
                }
            }
        }
        return res;
    }
  1. (四数和) 四重嵌套遍历
  2. 三重遍历,最后map
  3. 排序,双重遍历,最后两个数通过数组左右判断查找
滑动窗口
  1. Java 中优先队列并不可删除指定元素
  2. 暴力排序破解
  3. 使用双端队列,队列中存储下标,且队列中值保持降序,当新值插入时,若队尾小于该元素,则队尾弹出
  4. 使用下标来计算队首下标何时弹出,当下标等于i-k时,队首弹出,弹出后,下个元素仍为最大值
  5. 共产生n-k+1个元素
特性
  1. (134) 判断多个加油站,给定加油量以及消耗量,判断能否走完全程,起步量为0
    1. 当从i走到k时,油量消耗完,则意味着无论从i到k的那一站出发,都不可能走完全程,因为在这段范围内,到达每个站时,其存量是>=0的,故下一次应从k+1位置开始
    2. 仅需要一次遍历,当在k+1位置时,0到k是可以走通,当遍历完成时,说明k+1到n是可以走通的,故k+1到k+1是可以走通(存在唯一解)
    3. 通过一次遍历,判断从总量上判断能否走通,同时,在遍历过程中,假定起始点,定义余量,当余量为负值时,重置余量且更改起始点,至遍历完成
    4. 遍历完成后,从总量判断是否存在可行点,若存在,则可使用上述过程推断,得到起始点,若不存在,即使余量为正,也不存在可通过
  2. (767)字符串重构,不相邻
    1. 使用map存储字符串数量,然后每次去数量最多的两个进行排列,而后数量减一,重新排列
    2. 存入堆时,要先判断数量是否大于字母总数量的一半(考虑奇偶counts[i] <= (S.length() + 1) / 2),若大于,则不可行
    3. 使用最大堆进行排列,每次取出两个值,左右排列,重复取出·size>1,循环中取两次值
    4. 最终若仅剩一个值,则添加到最后,若为0,则直接输出

概念

字符串
  1. 处理字符串中的每一项时,使用char来进行处理
  2. 对于字符串中的数值,转换为char后可以if (c >= '0' && c <= '9') { num = num * 10 + c - '0';}来进行处理
  3. 字符串的反转,使用builder的reverse方法
  4. 对字符串中的字母进行排序,可以将其转换为char数组,对char进行排序,然后,重新生成新的字符串
  5. 对字符串数组进行排序,可以使用string的compareto方法
  1. 先进后出,仅仅操作栈顶元素
  2. 栈,回退数据,向某一方向延伸后可回退到初始方向;也可用于内部嵌套问题
  3. 栈弹出前,要判断大小是否还可以弹出数据
堆|优先队列
  1. PriorityQueuejava优先队列使用堆来实现,其中,可以在构造时指定比较器来确定其升序或者降序new PriorityQueue<Integer>((n1, n2) -> n1 - n2);使用lamb可以快速定义比较器
  2. 优先队列的时间复杂度于其大小有关,因此,可以使其大小维持在一常数级别,保证一定的速度,如if (heap.size() > k) heap.poll();
  3. 存值时,要考虑重复值问题
  4. 每次插入和弹出都会再次排序
最小值
  1. 数的最小值时为其序列为增序列
贪心算法
  1. 进行决策时,要考虑到临界值问题,如两数比较时,不足两数;亦或者左右比较交换后,会影响之前数据的升序或者降序
回溯法
  1. 字符串 正则匹配

    public boolean match(String str, String pattern) {
        return helper(str, pattern, "");
    }

    public boolean helper(String str, String pattern, String pre) {
        if (str.equals(pattern)) {
            return true;
        }
        if (pattern.length() == 0) {
            return false;
        }
        if (pattern.charAt(0) == '*') {
            return helper(str, pattern.substring(1), "");
        }
        boolean res = false;
        char[] strArrays = str.toCharArray();
        char[] patternArrays = pattern.toCharArray();

        if (strArrays.length > 0 && (strArrays[0] == patternArrays[0] || patternArrays[0] == '.')) {
            if (pattern.length() > 1 && patternArrays[1] == '*') {
                // * 代表0个值
                res = helper(str, pattern.substring(2), "");
                // * 代表1个值
                res = res || helper(str.substring(1), pattern.substring(2), "");
                // * 代表多个值
                res = res || helper(str.substring(1), pattern, "");

            } else {
                res = helper(str.substring(1), pattern.substring(1), str.substring(0, str.length() - 1));
            }
        } else {
            if (pattern.length() > 1 && patternArrays[1] == '*') {
                // * 代表0个值
                res = helper(str, pattern.substring(2), "");
            }
        }
        return res;
    }
分治算法(递归)
  1. 当问题规模可以缩小且缩小后的处理过程与原过程相同
  2. 注意参数的类型
  3. 如果在合并操作是,不进行结果的修改或删除,可以不使用深拷贝
  4. 参数在传入下一级之前,如有需要,要进行深拷贝
卡特兰数
  1. 若 令 h ( 0 ) = 1 , h ( 1 ) = 1 , c a t a l a n 数 满 足 递 推 式 : h ( n ) = h ( 0 ) ∗ h ( n − 1 ) + h ( 1 ) ∗ h ( n − 2 ) + . . . + h ( n − 1 ) h ( 0 ) ( n > = 2 ) 若令h(0)=1,h(1)=1,catalan数满足递推式:h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (n>=2) h(0)=1,h(1)=1catalanh(n)=h(0)h(n1)+h(1)h(n2)+...+h(n1)h(0)(n>=2),递推公式的通解: h ( n ) = C ( 2 n , n ) / n + 1 ( 或 者 C ( 2 n , n ) − C ( 2 n , n + 1 ) ) ) h(n)=C(2n,n)/n+1(或者C(2n,n)-C(2n,n+1))) h(n)=C(2n,n)/n+1(C(2n,n)C(2n,n+1)))
  2. 一个序列,有规律的根据其中的每一个点将完整的序列划分为两个序列,每个点得到的结果(左右序列的组合)相加;同时,划分出的序列又进行同样的步骤,进行划分;当序列足够小时,得到结果
  3. 注意:
    1. 注意分割点与左右序列的关系
    2. 序列会被不断缩减,当最小化时,得到结果
    3. 左右序列中不包含分割点
  4. 构造二叉搜索树:
    1. 以初始序列中每一个节点为根
    2. 每一个根可以将整个序列划分为两部分;求出以左右序列中每个点为根所生成的所有属性结构
    3. 已经被划分的两部分序列还可以继续划分,直至长度为0或一
    4. 至最小情况时,构造树型结构返回,因为其为组合,故返回结果为集合
    5. 上一层获取到返回结果后,要进行左右序列结果的组合,才能得到对应序列以该点为根的所有树形结构,同时,将所在序列中不同点为根所生成的结构存储到集合中返回到上一级;
    6. 与普通递归的区别在与于,合并时,进行了结果的组合处理,同时,也进行了层次遍历
  5. 细节:
    1. 递归方法中,参数表示序列,以开始和结束坐标表示
    2. 返回结果为集合,要以所使用的的根节点为根节点进行组合
    3. 拆分序列时,以根节点左右划分序列,终止条件为划分的序列start>end,或者start=end;此时序列长度为0或者1,当序列长度为2时,仍可以继续划分
    4. 节点中可以存空
    5. 相同的属性结构会生成多次,但其本应该生成对次
    6. 要以参数传来的序列中的每一个值为根节点求解
  6. 括号问题
    1. 以某个出栈的位置来划分左右序列,该位置与左右序列的关系为该位置的括号包含着已经出栈的序列,即左序列
    2. n对括号,求解为其中的一对括号,包含着其他括号,从1到n,包含着的为左序列,未包含的为右序列
    3. 划分序列时,不包含当前括号,当前括号包含左括号
       for(String l:left){
               for(String r:right){
                   list.add("("+l+")"+r);
               }
           }
  1. 给出一个n,要求一个长度为2n的01序列,使得序列的任意前缀中1的个数不少于0的个数;
    1. 1表示进栈,0表示出栈,借用栈想法求解
基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip基于MATLAB实现旅行推销员问题(TSP)的代码+项目说明(课程大作业)+测试数据.zip 【备注】 1、该资源内项目代码百分百可运行,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值