程序员编程艺术:第五章、寻找和为定值的两个或多个数

作者:July,yansha,zhouzhenren。
    致谢:微软100题实现组,编程艺术室。
    微博:http://weibo.com/julyweibo   。
    出处:http://blog.csdn.net/v_JULY_v 
    wiki:http://tctop.wikispaces.com/
------------------------------

前奏

希望此编程艺术系列能给各位带来的是一种方法,一种创造力,一种举一反三的能力。本章依然同第四章一样,选取比较简单的面试题,恭祝各位旅途愉快。同样,有任何问题,欢迎不吝指正。谢谢。

第一节、寻找和为定值的两个数
第14题(数组):
题目:输入一个数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。

分析

咱们试着一步一步解决这个问题(注意阐述中数列有序无序的区别):

  1. 直接穷举,从数组中任意选取两个数,判定它们的和是否为输入的那个数字。此举复杂度为O(N^2)。很显然,我们要寻找效率更高的解法。
  2. 题目相当于,对每个a[i],查找sum-a[i]是否也在原始序列中,每一次要查找的时间都要花费为O(N),这样下来,最终找到两个数还是需要O(N^2)的复杂度。那如何提高查找判断的速度呢?答案是二分查找,可以将O(N)的查找时间提高到O(logN),这样对于N个a[i],都要花logN的时间去查找相对应的sum-a[i]是否在原始序列中,总的时间复杂度已降为O(N*logN),且空间复杂度为O(1)。(如果有序,直接二分O(N*logN),如果无序,先排序后二分,复杂度同样为O(N*logN+N*logN)=O(N*logN),空间总为O(1))。
  3. 有没有更好的办法呢?咱们可以依据上述思路2的思想,a[i]在序列中,如果a[i]+a[k]=sum的话,那么sum-a[i](a[k])也必然在序列中,举个例子,如下:
    原始序列:1、 2、 4、 7、11、15     用输入数字15减一下各个数,得到对应的序列为:
    对应序列:14、13、11、8、4、 0     
    第一个数组以一指针i 从数组最左端开始向右扫描,第二个数组以一指针j 从数组最右端开始向左扫描,如果下面出现了和上面一样的数,即a[*i]=a[*j],就找出这俩个数来了。如上,i,j最终在第一个,和第二个序列中找到了相同的数4和11,,所以符合条件的两个数,即为4+11=15。怎么样,两端同时查找,时间复杂度瞬间缩短到了O(N),但却同时需要O(N)的空间存储第二个数组(@飞羽:要达到O(N)的复杂度,第一个数组以一指针i 从数组最左端开始向右扫描,第二个数组以一指针j 从数组最右端开始向左扫描,首先初始i指向元素1,j指向元素0,谁指的元素小,谁先移动,由于1(i)>0(j),所以i不动,j向左移动。然后j移动到元素4发现大于元素1,故而停止移动j,开始移动i,直到i指向4,这时,i指向的元素与j指向的元素相等,故而判断4是满足条件的第一个数;然后同时移动i,j再进行判断,直到它们到达边界)。
  4. 当然,你还可以构造hash表,正如编程之美上的所述,给定一个数字,根据hash映射查找另一个数字是否也在数组中,只需用O(1)的时间,这样的话,总体的算法通上述思路3 一样,也能降到O(N),但有个缺陷,就是构造hash额外增加了O(N)的空间,此点同上述思路 3。不过,空间换时间,仍不失为在时间要求较严格的情况下的一种好办法。
  5. 如果数组是无序的,先排序(n*logn),然后用两个指针i,j,各自指向数组的首尾两端,令i=0,j=n-1,然后i++,j--,逐次判断a[i]+a[j]?=sum,如果某一刻a[i]+a[j]&gt;sum,则要想办法让sum的值减小,所以此刻i不动,j--,如果某一刻a[i]+a[j]<sum,则要想办法让sum的值增大,所以此刻i++,j不动。所以,数组无序的时候,时间复杂度最终为O(n*logn+n)=O(n*logn),若原数组是有序的,则不需要事先的排序,直接O(n)搞定,且空间复杂度还是O(1),此思路是相对于上述所有思路的一种改进。(如果有序,直接两个指针两端扫描,时间O(N),如果无序,先排序后两端扫描,时间O(N*logN+N)=O(N*logN),空间始终都为O(1))。(与上述思路2相比,排序后的时间开销由之前的二分的n*logn降到了扫描的O(N))。

总结

  • 不论原序列是有序还是无序,解决这类题有以下三种办法:1、二分(若无序,先排序后二分),时间复杂度总为O(n*logn),空间复杂度为O(1);2、扫描一遍X-S[i]  映射到一个数组或构造hash表,时间复杂度为O(n),空间复杂度为O(n);3、两个指针两端扫描(若无序,先排序后扫描),时间复杂度最后为:有序O(n),无序O(n*logn+n)=O(n*logn),空间复杂度都为O(1)。
  • 所以,要想达到时间O(N),空间O(1)的目标,除非原数组是有序的(指针扫描法),不然,当数组无序的话,就只能先排序,后指针扫描法或二分(时间n*logn,空间O(1)),或映射或hash(时间O(n),空间O(n))。时间或空间,必须牺牲一个,自个权衡吧。
  • 综上,若是数组有序的情况下,优先考虑两个指针两端扫描法,以达到最佳的时(O(N)),空(O(1))效应。否则,如果要排序的话,时间复杂度最快当然是只能达到N*logN,空间O(1)则是不在话下。

代码:

ok,在进入第二节之前,咱们先来实现思路5(这里假定数组已经是有序的),代码可以如下编写(两段代码实现):

[cpp] view plaincopyprint?
  1. //代码一
  2. //O(N)
  3. Pair findSum(int *s,int n,int x)
  4. {
  5. //sort(s,s+n);   如果数组非有序的,那就事先排好序O(N*logN)
  6. int *begin=s;
  7. int *end=s+n-1;
  8. while(begin<end)    //俩头夹逼,或称两个指针两端扫描法,很经典的方法,O(N)
  9. {
  10. if(*begin+*end>x)
  11. {
  12. --end;
  13. }
  14. else if(*begin+*end<x)
  15. {
  16. ++begin;
  17. }
  18. else
  19. {
  20. return Pair(*begin,*end);
  21. }
  22. }
  23. return Pair(-1,-1);
  24. }
  25. //或者如下编写,
  26. //代码二
  27. //copyright@ zhedahht && yansha
  28. //July、updated,2011.05.14。
  29. bool find_num(int data[], unsigned int length, int sum, int& first_num, int& second_num)
  30. {
  31. if(length < 1)
  32. return true;
  33. int begin = 0;
  34. int end = length - 1;
  35. while(end > begin)
  36. {
  37. long current_sum = data[begin] + data[end];
  38. if(current_sum == sum)
  39. {
  40. first_num = data[begin];
  41. second_num = data[end];
  42. return true;
  43. }
  44. else if(current_sum > sum)
  45. end--;
  46. else
  47. begin++;
  48. }
  49. return false;
  50. }

//代码一 //O(N) Pair findSum(int *s,int n,int x) { //sort(s,s+n); 如果数组非有序的,那就事先排好序O(N*logN) int *begin=s; int *end=s+n-1; while(begin<end) //俩头夹逼,或称两个指针两端扫描法,很经典的方法,O(N) { if(*begin+*end>x) { --end; } else if(*begin+*end<x) { ++begin; } else { return Pair(*begin,*end); } } return Pair(-1,-1); } //或者如下编写, //代码二 //copyright@ zhedahht && yansha //July、updated,2011.05.14。 bool find_num(int data[], unsigned int length, int sum, int& first_num, int& second_num) { if(length < 1)return true;int begin = 0;int end = length - 1;while(end > begin){long current_sum = data[begin] + data[end];if(current_sum == sum){first_num = data[begin];second_num = data[end];return true;}else if(current_sum > sum)end--;elsebegin++;}return false; }

扩展:
1、如果在返回找到的两个数的同时,还要求你返回这两个数的位置列?
2、如果把题目中的要你寻找的两个数改为“多个数”,或任意个数列?(请看下面第二节)
3、二分查找时: left <= right,right = middle - 1;left < right,right = middle;

//算法所操作的区间,是左闭右开区间,还是左闭右闭区间,这个区间,需要在循环初始化,
//循环体是否终止的判断中,以及每次修改left,right区间值这三个地方保持一致,否则就可能出错.

//二分查找实现一
int search(int array[], int n, int v)
{
    int left, right, middle;
 
    left = 0, right = n - 1;
 
    while (left <= right)
    {
        middle = left + (right-left)/2;   
        if (array[middle] > v)
        {
            right = middle - 1;
        }
        else if (array[middle] < v)
        {
            left = middle + 1;
        }
        else
        {
            return middle;
        }
    }
 
    return -1;
}

//二分查找实现二
int search(int array[], int n, int v)
{
    int left, right, middle;
 
    left = 0, right = n;
 
    while (left < right)
    {
        middle = left + (right-left)/2;    
  
        if (array[middle] > v)
        {
            right = middle;
        }
        else if (array[middle] < v)
        {
            left = middle + 1;
        }
        else
        {
            return middle;
        }
    }
 
    return -1;
}

第二节、寻找和为定值的多个数
第21题(数组)
2010年中兴面试题
编程求解:
输入两个整数 n 和 m,从数列1,2,3.......n 中 随意取几个数,
使其和等于 m ,要求将其中所有的可能组合列出来。

解法一
我想,稍后给出的程序已经足够清楚了,就是要注意到放n,和不放n个区别,即可,代码如下:

[cpp] view plaincopyprint?
  1. // 21题递归方法
  2. //copyright@ July && yansha
  3. //July、yansha,updated。
  4. #include<list>
  5. #include<iostream>
  6. using namespace std;
  7. list<int>list1;
  8. void find_factor(int sum, int n)
  9. {
  10. // 递归出口
  11. if(n <= 0 || sum <= 0)
  12. return;
  13. // 输出找到的结果
  14. if(sum == n)
  15. {
  16. // 反转list
  17. list1.reverse();
  18. for(list<int>::iterator iter = list1.begin(); iter != list1.end(); iter++)
  19. cout << *iter << " + ";
  20. cout << n << endl;
  21. list1.reverse();
  22. }
  23. list1.push_front(n);      //典型的01背包问题
  24. find_factor(sum-n, n-1);   //放n,n-1个数填满sum-n
  25. list1.pop_front();
  26. find_factor(sum, n-1);     //不放n,n-1个数填满sum
  27. }
  28. int main()
  29. {
  30. int sum, n;
  31. cout << "请输入你要等于多少的数值sum:" << endl;
  32. cin >> sum;
  33. cout << "请输入你要从1.....n数列中取值的n:" << endl;
  34. cin >> n;
  35. cout << "所有可能的序列,如下:" << endl;
  36. find_factor(sum,n);
  37. return 0;
  38. }

// 21题递归方法 //copyright@ July && yansha //July、yansha,updated。 #include<list> #include<iostream> using namespace std;list<int>list1; void find_factor(int sum, int n) {// 递归出口if(n <= 0 || sum <= 0)return;// 输出找到的结果if(sum == n){// 反转listlist1.reverse();for(list<int>::iterator iter = list1.begin(); iter != list1.end(); iter++)cout << *iter << " + ";cout << n << endl;list1.reverse(); }list1.push_front(n); //典型的01背包问题find_factor(sum-n, n-1); //放n,n-1个数填满sum-nlist1.pop_front();find_factor(sum, n-1); //不放n,n-1个数填满sum }int main() {int sum, n;cout << "请输入你要等于多少的数值sum:" << endl;cin >> sum;cout << "请输入你要从1.....n数列中取值的n:" << endl;cin >> n;cout << "所有可能的序列,如下:" << endl;find_factor(sum,n);return 0; }

解法二
@zhouzhenren:
这个问题属于子集和问题(也是背包问题)。本程序采用 回溯法+剪枝
X数组是解向量,t=∑(1,..,k-1)Wi*Xi, r=∑(k,..,n)Wi
若t+Wk+W(k+1)<=M,则Xk=true,递归左儿子(X1,X2,..,X(k-1),1);否则剪枝;
若t+r-Wk>=M && t+W(k+1)<=M,则置Xk=0,递归右儿子(X1,X2,..,X(k-1),0);否则剪枝;
本题中W数组就是(1,2,..,n),所以直接用k代替WK值。

代码编写如下:

[cpp] view plaincopyprint?
  1. //copyright@ 2011 zhouzhenren
  2. //输入两个整数 n 和 m,从数列1,2,3.......n 中 随意取几个数,
  3. //使其和等于 m ,要求将其中所有的可能组合列出来。
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <memory.h>
  7. /**
  8. * 输入t, r, 尝试Wk
  9. */
  10. void sumofsub(int t, int k ,int r, int& M, bool& flag, bool* X)
  11. {
  12. X[k] = true;   // 选第k个数
  13. if (t + k == M) // 若找到一个和为M,则设置解向量的标志位,输出解
  14. {
  15. flag = true;
  16. for (int i = 1; i <= k; ++i)
  17. {
  18. if (X[i] == 1)
  19. {
  20. printf("%d ", i);
  21. }
  22. }
  23. printf("/n");
  24. }
  25. else
  26. {   // 若第k+1个数满足条件,则递归左子树
  27. if (t + k + (k+1) <= M)
  28. {
  29. sumofsub(t + k, k + 1, r - k, M, flag, X);
  30. }
  31. // 若不选第k个数,选第k+1个数满足条件,则递归右子树
  32. if ((t + r - k >= M) && (t + (k+1) <= M))
  33. {
  34. X[k] = false;
  35. sumofsub(t, k + 1, r - k, M, flag, X);
  36. }
  37. }
  38. }
  39. void search(int& N, int& M)
  40. {
  41. // 初始化解空间
  42. bool* X = (bool*)malloc(sizeof(bool) * (N+1));
  43. memset(X, false, sizeof(bool) * (N+1));
  44. int sum = (N + 1) * N * 0.5f;
  45. if (1 > M || sum < M) // 预先排除无解情况
  46. {
  47. printf("not found/n");
  48. return;
  49. }
  50. bool f = false;
  51. sumofsub(0, 1, sum, M, f, X);
  52. if (!f)
  53. {
  54. printf("not found/n");
  55. }
  56. free(X);
  57. }
  58. int main()
  59. {
  60. int N, M;
  61. printf("请输入整数N和M/n");
  62. scanf("%d%d", &N, &M);
  63. search(N, M);
  64. return 0;
  65. }

//copyright@ 2011 zhouzhenren//输入两个整数 n 和 m,从数列1,2,3.......n 中 随意取几个数, //使其和等于 m ,要求将其中所有的可能组合列出来。#include <stdio.h> #include <stdlib.h> #include <memory.h>/** * 输入t, r, 尝试Wk*/ void sumofsub(int t, int k ,int r, int& M, bool& flag, bool* X) {X[k] = true; // 选第k个数if (t + k == M) // 若找到一个和为M,则设置解向量的标志位,输出解{flag = true;for (int i = 1; i <= k; ++i){if (X[i] == 1){printf("%d ", i);}}printf("/n");}else{ // 若第k+1个数满足条件,则递归左子树if (t + k + (k+1) <= M){sumofsub(t + k, k + 1, r - k, M, flag, X);}// 若不选第k个数,选第k+1个数满足条件,则递归右子树if ((t + r - k >= M) && (t + (k+1) <= M)){X[k] = false;sumofsub(t, k + 1, r - k, M, flag, X);}} }void search(int& N, int& M) {// 初始化解空间bool* X = (bool*)malloc(sizeof(bool) * (N+1));memset(X, false, sizeof(bool) * (N+1));int sum = (N + 1) * N * 0.5f;if (1 > M || sum < M) // 预先排除无解情况{printf("not found/n");return;}bool f = false;sumofsub(0, 1, sum, M, f, X);if (!f){printf("not found/n");}free(X); }int main() {int N, M;printf("请输入整数N和M/n");scanf("%d%d", &N, &M);search(N, M);return 0; }

扩展:

1、从一列数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的(网易)。

2、有两个序列a,b,大小都为n,序列元素的值任意整数,无序;
要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。
例如: 
var a=[100,99,98,1,2, 3];
var b=[1, 2, 3, 4,5,40];(微软100题第32题)。

@well:[fairywell]:
给出扩展问题 1 的一个解法:
1、从一列数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的(网易)。
双端 LIS 问题,用 DP 的思想可解,目标规划函数 max{ b[i] + c[i] - 1 }, 其中 b[i] 为从左到右, 0 ~ i 个数之间满足递增的数字个数; c[i] 为从右到左, n-1 ~ i 个数之间满足递增的数字个数。最后结果为 n - max + 1。其中 DP 的时候,可以维护一个 inc[] 数组表示递增数字序列,inc[i] 为从小到大第 i 大的数字,然后在计算 b[i] c[i] 的时候使用二分查找在 inc[] 中找出区间 inc[0] ~ inc[i-1] 中小于 a[i] 的元素个数(low)。
源代码如下:

[cpp] view plaincopyprint?
  1. /**
  2. * The problem:
  3. * 从一列数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的(网易)。
  4. * use binary search, perhaps you should compile it with -std=c99
  5. * fairywell 2011
  6. */
  7. #include <stdio.h>
  8. #define MAX_NUM    (1U<<31)
  9. int
  10. main()
  11. {
  12. int i, n, low, high, mid, max;
  13. printf("Input how many numbers there are: ");
  14. scanf("%d/n", &n);
  15. /* a[] holds the numbers, b[i] holds the number of increasing numbers
  16. * from a[0] to a[i], c[i] holds the number of increasing numbers
  17. * from a[n-1] to a[i]
  18. * inc[] holds the increasing numbers
  19. * VLA needs c99 features, compile with -stc=c99
  20. */
  21. double a[n], b[n], c[n], inc[n];
  22. printf("Please input the numbers:/n");
  23. for (i = 0; i < n; ++i) scanf("%lf", &a[i]);
  24. // update array b from left to right
  25. for (i = 0; i < n; ++i) inc[i] = (unsigned) MAX_NUM;
  26. //b[0] = 0;
  27. for (i = 0; i < n; ++i) {
  28. low = 0; high = i;
  29. while (low < high) {
  30. mid = low + (high-low)*0.5;
  31. if (inc[mid] < a[i]) low = mid + 1;
  32. else high = mid;
  33. }
  34. b[i] = low + 1;
  35. inc[low] = a[i];
  36. }
  37. // update array c from right to left
  38. for (i = 0; i < n; ++i) inc[i] = (unsigned) MAX_NUM;
  39. //c[0] = 0;
  40. for (i = n-1; i >= 0; --i) {
  41. low = 0; high = i;
  42. while (low < high) {
  43. mid = low + (high-low)*0.5;
  44. if (inc[mid] < a[i]) low = mid + 1;
  45. else high = mid;
  46. }
  47. c[i] = low + 1;
  48. inc[low] = a[i];
  49. }
  50. max = 0;
  51. for (i = 0; i < n; ++i )
  52. if (b[i]+c[i] > max) max = b[i] + c[i];
  53. printf("%d number(s) should be erased at least./n", n+1-max);
  54. return 0;
  55. }

/** * The problem: * 从一列数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的(网易)。 * use binary search, perhaps you should compile it with -std=c99 * fairywell 2011 */ #include <stdio.h>#define MAX_NUM (1U<<31)int main() {int i, n, low, high, mid, max;printf("Input how many numbers there are: ");scanf("%d/n", &n);/* a[] holds the numbers, b[i] holds the number of increasing numbers* from a[0] to a[i], c[i] holds the number of increasing numbers* from a[n-1] to a[i]* inc[] holds the increasing numbers* VLA needs c99 features, compile with -stc=c99*/double a[n], b[n], c[n], inc[n];printf("Please input the numbers:/n");for (i = 0; i < n; ++i) scanf("%lf", &a[i]);// update array b from left to rightfor (i = 0; i < n; ++i) inc[i] = (unsigned) MAX_NUM;//b[0] = 0;for (i = 0; i < n; ++i) {low = 0; high = i;while (low < high) {mid = low + (high-low)*0.5;if (inc[mid] < a[i]) low = mid + 1;else high = mid;}b[i] = low + 1;inc[low] = a[i];}// update array c from right to leftfor (i = 0; i < n; ++i) inc[i] = (unsigned) MAX_NUM;//c[0] = 0;for (i = n-1; i >= 0; --i) {low = 0; high = i;while (low < high) {mid = low + (high-low)*0.5;if (inc[mid] < a[i]) low = mid + 1;else high = mid;}c[i] = low + 1;inc[low] = a[i];}max = 0;for (i = 0; i < n; ++i )if (b[i]+c[i] > max) max = b[i] + c[i];printf("%d number(s) should be erased at least./n", n+1-max);return 0; }

@yansha:fairywell的程序很赞,时间复杂度O(nlogn),这也是我能想到的时间复杂度最优值了。不知能不能达到O(n)。

扩展题第2题

当前数组a和数组b的和之差为
    A = sum(a) - sum(b)

a的第i个元素和b的第j个元素交换后,a和b的和之差为
    A' = sum(a) - a[i] + b[j] - (sum(b) - b[j] + a[i])
           = sum(a) - sum(b) - 2 (a[i] - b[j])
           = A - 2 (a[i] - b[j])

设x = a[i] - b[j],得
    |A| - |A'| = |A| - |A-2x|

假设A > 0,

当x 在 (0,A)之间时,做这样的交换才能使得交换后的a和b的和之差变小,x越接近A/2效果越好,
    如果找不到在(0,A)之间的x,则当前的a和b就是答案。

所以算法大概如下:
    在a和b中寻找使得x在(0,A)之间并且最接近A/2的i和j,交换相应的i和j元素,重新计算A后,重复前面的步骤直至找不到(0,A)之间的x为止。

接上,@yuan:
a[i]-b[j]要接近A/2,则可以这样想,
我们可以对于a数组的任意一个a[k],在数组b中找出与a[k]-C最接近的数(C就是常数,也就是0.5*A)
这个数要么就是a[k]-C,要么就是比他稍大,要么比他稍小,所以可以要二分查找。

查找最后一个小于等于a[k]-C的数和第一个大于等于a[k]-C的数,
然后看哪一个与a[k]-C更加接近,所以T(n) = nlogn。

除此之外,受本文读者xiafei1987128启示,有朋友在stacoverflow上也问过一个类似的题,:-),见此:http://stackoverflow.com/questions/9047908/swap-the-elements-of-two-sequences-such-that-the-difference-of-the-element-sums。感兴趣的可以看看。

本章完。


版权所有,本人对本blog内所有任何内容享有版权及著作权。实要转载,请以链接形式注明出处。

版权声明:本文为博主原创文章,未经博主允许不得转载。

程序员编程艺术:第五章、寻找满足和为定值的两个或多个数相关推荐

  1. 程序员编程艺术:第二章、字符串是否包含问题

    程序员编程艺术:第二章.字符串是否包含及相关问题扩展 作者:July,yansha. 时间:二零一一年四月二十三日. 致谢:老梦,nossiac,Hession,Oliver,luuillu,雨翔,啊 ...

  2. 程序员编程艺术第十一章:最长公共子序列(LCS)问题

    程序员编程艺术第十一章:最长公共子序列(LCS)问题 0.前言 程序员编程艺术系列重新开始创作了(前十章,请参考程序员编程艺术第一~十章集锦与总结).回顾之前的前十章,有些代码是值得商榷的,因当时的代 ...

  3. 程序员编程艺术:第九章、闲话链表追赶问题

    程序员编程艺术:第九章.闲话链表追赶问题 作者:July.狂想曲创作组. 出处:http://blog.csdn.net/v_JULY_v . 前奏     有这样一个问题:在一条左右水平放置的直线轨 ...

  4. 程序员编程艺术第二十七章:不改变正负数相对顺序重新排列数组(无解?)

    第二十七章:不改变正负数之间相对顺序重新排列数组.时间O(N),空间O(1) 前言 本文开始之前,顺道说个事:CSDN最近开始评选10大博客专栏,投票地址为:http://event.blog.csd ...

  5. 程序员编程艺术 第六章 求解500万以内的亲和数

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 第六章. ...

  6. 程序员编程艺术第一~二十七章集锦与总结(教你如何编程),及PDF免分下载

    程序员编程艺术第一~二十七章集锦与总结(教你如何编程) 作者:July.编程艺术室 出处:结构之法算法之道blog 一.引言 自从去年7月份朋友花明月黯帮我制作了十三个经典算法研究的PDF文档(最新的 ...

  7. 程序员编程艺术:第三章、寻找最小的k个数

    程序员编程艺术:第三章.寻找最小的k个数 作者:July. 时间:二零一一年四月二十八日. 致谢:litaoye, strugglever,yansha,luuillu,Sorehead,及狂想曲创作 ...

  8. 程序员编程艺术第三十四~三十五章:格子取数问题,完美洗牌算法

    第三十四~三十五章:格子取数,完美洗牌算法 作者:July.caopengcs.绿色夹克衫.致谢:西芹_new,陈利人, Peiyush Jain,白石,zinking. 时间:二零一三年八月二十三日 ...

  9. 程序员编程艺术第三十四 三十五章 格子取数问题,完美洗牌算法

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 第三十四 ...

最新文章

  1. python file does not exist_python – os.path.exists()的谎言
  2. Puppet客户端自动安装脚本
  3. Visual Basic 9.0 前沿播报·静态篇(一)局部变量类型推测和数组初始化器
  4. 计算机网络实用期末试题和答案,计算机网络期末考试试题及答案(1)
  5. 全球破300万!小米11系列高端市场地位稳了
  6. 文字组合生成器_万字长文神器,原来只是固定数据库排列组合而成
  7. java 编辑二进制文件_java写二进制文件,不能直接编辑,该怎么操作?
  8. java工程师占比_2020年Java工程师就业分析
  9. 数据抓取的艺术(二)
  10. HeadFirstJava学习心得——网络编程
  11. cad插入块_软件CAD | 块amp;点工具
  12. php使用adodb下载,ADODB的使用
  13. Cheat Engine(CE)-----下载安装及入门
  14. Python实现--使用微信定时每天和女友发送定制消息(附代码教程)
  15. 各软件版本、仓库、官网地址
  16. Kafka ETL 之后,我们将如何定义新一代实时数据集成解决方案?
  17. Gradle 学习 ----Gradle 进阶说明
  18. Linux的实时监测命令(watch)
  19. lab值意义_色差仪lab值含义是什么?
  20. 机器学习(三)——梯度下降

热门文章

  1. 史上最实用mysql参数之一-----sql_safe_updates
  2. Maven中的pom.properties文件
  3. Linux中,Tomcat安装
  4. JQuery学习之一:(加载函数,获取画面元素,一些简单的函数【each】【find】【focuse】【blur】)
  5. 文件下载时,IE与FireFox对文件名编码的不同处理! Content-Disposition
  6. 域 禁用计算机,域成员 在 Windows 10 (禁用计算机帐户) - Windows security | Microsoft Docs...
  7. linux命令地址,[命令] Linux IP 命令 IP(管理地址)
  8. Vue首页加载过慢 解决方案
  9. ubuntu18.04 没声音解决方案(坑自己版)
  10. -bash : ** : command not found的问题解决(图文详解)