[2018大華軟件創新挑戰賽] 初賽1~10題多種思路總結

 [2018大華軟件創新挑戰賽] 初賽1~10題多種思路總結html

 

賽題以及注意事項(下載):https://files.cnblogs.com/files/usingnamespace-caoliu/%E5%88%9D%E8%B5%9B.rarnode

 


 

第一題(已優化):算法

  給定一個正數數組,找出不相鄰元素的子序列的和的最大值。如:二、五、三、9應該返回14(5+9);八、五、三、九、1應該返回17(8+9);5 4 10 100 10 5應該返回110(5+100+5);數組

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 
 4 int max = 0;  5 
 6 void combination(int* arr,int i,int len)  7 {  8     if(i >= len)  9  { 10         int sum = 0; 11         for(int j=0; j<len-1; j++) 12  { 13             if(arr[j] && arr[j+1]) return; 14             sum += arr[j]; 15  } 16 
17         sum += arr[len-1]; 18         
19         if(sum > max) 20  { 21             max = sum; 22  } 23         return; 24  } 25 
26     int tmep = arr[i]; 27     arr[i] = 0; 28     combination(arr,i+1,len); 29     arr[i] = tmep; 30     combination(arr,i+1,len); 31 } 32 
33 int main() 34 { 35     int t = 0; 36     scanf("%d",&t); 37     while(t--) 38  { 39         int n = 0; 40         scanf("%d",&n); 41         int arr[n]; 42         for(int i=0; i<n; i++) 43  { 44             scanf("%d",&arr[i]); 45  } 46         combination(arr,0,n); 47         printf("%d\n",max); 48  } 49 }
View Code

思路:與大華模擬題第四題相同,利用遞歸函數遍歷數組中任意位數相加的和,再經過if(arr[j] && arr[j+1]) return;剔除全部包含相鄰元素的子序列的和,最後遍歷全部符合題意的和,比較後便可得出不相鄰元素的子序列的和的最大值。框架

總結:該方法爲通用解法而非最優解,本質爲遞歸嵌套,最終會造成一種相似於二叉樹的結構,可經過更改遞歸最後一層的斷定條件來實現絕大部分需遍歷的功能。ide

 


 

第二題(已優化):函數

  給定一個鏈表,實現一個函數,將鏈表中每k個節點進行翻轉,若最後一組節點數量不足k個,則按實際個數翻轉。例如:給定鏈表1->2->3->4->5->6->7->8->NULL,k=3,翻轉後輸出3->2->1->6->5->4->8->7->NULL。
翻轉函數reverse有兩個參數,分別爲鏈表頭指針和翻轉步長k。測試

 1 #include <stdio.h>
 2 
 3 void _release(int* arr,int len)  4 {  5     for(int i=0; i<len/2; i++)  6  {  7         int t = arr[i];  8         arr[i] = arr[len-1-i];  9         arr[len-1-i] = t; 10  } 11 } 12 
13 void release(int* arr,int k,int n) 14 { 15     if(k > n) 16  { 17  _release(arr,n); 18         return; 19  } 20  _release(arr,k); 21     release(arr+k,k,n-k); 22 } 23 
24 int main() 25 { 26     int t = 0; 27     scanf("%d",&t); 28 
29     while(t--) 30  { 31         int n = 0; 32         scanf("%d",&n); 33         int arr[n]; 34         for(int i=0; i<n; i++) 35  { 36             scanf("%d",&arr[i]); 37  } 38 
39         int k = 0; 40         scanf("%d",&k); 41  release(arr,k,n); 42         
43         for(int i=0; i<n; i++) 44  { 45             printf("%d ",arr[i]); 46  } 47         printf("\n"); 48  } 49 }
View Code(思路1)
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <stdbool.h>
 4 
 5 //#include "linked_list.h"
 6 
 7 typedef int T;  8 
 9 typedef struct Node  10 {  11     //節點保存的數據
 12  T data;  13     //下一個節點的位置
 14     struct Node* next;  15 }Node,Link;  16 
 17 //建立一個鏈表
 18 Link* creat_link()  19 {  20     //建立一個節點,表示頭節點,該節點並不保存數據
 21     Link* head = (Link*)malloc(sizeof(Node));  22     //讓頭節點的next置NULL,表示鏈表爲空
 23     head->next = NULL;  24     //返回頭的地址
 25     return head;  26 }  27 
 28 //清空鏈表
 29 void clear_link(Link* link)  30 {  31     Node* node = link->next;  32     while(node != NULL)  33  {  34         Node* tmp = node;  35         node = node->next;  36         free(tmp);  37  }  38     link->next = NULL;  39 }  40 
 41 //銷燬鏈表
 42 void destroy_link(Link* link)  43 {  44  clear_link(link);  45     free(link);  46     link = NULL;  47 }  48 
 49 //判斷鏈表是否爲空
 50 bool emtpy_link(Link* link)  51 {  52     return !link->next;  53 }  54 
 55 //得到鏈表裏元素的個數
 56 size_t size_link(Link* link)  57 {  58     size_t i = 0;  59     //用node記錄頭節點的下一個位置
 60     Node* node = link->next;  61     //只要node不爲NULL,表示該節點存在
 62     while(node != NULL)  63  {  64         //讓node繼續指向下一個節點
 65         node = node->next;  66         i++;  67  }  68     return i;  69 }  70 
 71 //返回下標爲index的前一個節點
 72 Node* getNode_link(Link* link, int index)  73 {  74     Node* node = link;  75     //若是index=0 其前一個節點就爲link ,並不會進入下面循環
 76     for(int i=0; node != NULL && i<index; i++)  77  {  78         node = node->next;  79  }  80     return node;  81 }  82 
 83 //更新鏈表下標爲index的節點的值
 84 bool update_link(Link* link, int index, T value)  85 {  86     if(index < 0 || index > size_link(link)-1)  87         return false;  88     Node* node = getNode_link(link, index+1);  89     node->data = value;  90     return true;  91 }  92 
 93 //插入一個元素到指定位置 index取值範圍[0,size_link(Link* link)]
 94 bool insert_link(Link* link, int index, T value)  95 {  96     if(index < 0 || index > size_link(link))  97         return false;  98     //獲得下標爲index位置的前一個節點
 99     Node* prevNode = getNode_link(link, index); 100     //申請內存,用於保存須要插入的數據
101     Node* node = (Node*)malloc(sizeof(Node)); 102     node->data = value; 103     //插入節點的下一個節點指向index前一個節點的後節點
104     node->next = prevNode->next; 105     //讓index的前節點的下一個節點指向當前插入的節點
106     prevNode->next = node; 107     return true; 108 } 109 //插入一個元素到鏈表末尾
110 bool insertBack_link(Link* link, T value) 111 { 112     return insert_link(link, size_link(link), value); 113 } 114 //插入一個元素到鏈表首部
115 bool insertFront_link(Link* link, T value) 116 { 117     return insert_link(link, 0, value); 118 } 119 
120 //刪除指定下標的元素
121 bool delete_link(Link* link, int index) 122 { 123     if(index < 0 || index > size_link(link)-1) 124         return false; 125     //得到須要刪除節點的前一個節點
126     Node* prevNode = getNode_link(link, index); 127     //保存要刪除的節點,用於釋放內存
128     Node* node  = prevNode->next; 129     //讓要刪除節點的前一個節點指向要刪除節點的後一個節點
130     prevNode->next = prevNode->next->next; 131     free(node); 132     return true; 133 } 134 
135 //刪除元素爲value的全部節點,返回值表示該鏈表的數據是否發生變化
136 bool deleteDatas_link(Link* link, T value) 137 { 138     //做爲是否刪除成功的一個標誌
139     bool flag = false; 140     Node* node = link->next; 141     for(int i = 0; node != NULL; i++) 142  { 143         if(node->data == value) 144  { 145  delete_link(link, i); 146             //刪除後斷定下標前移
147             i--; 148             flag = true; 149  } 150         node = node->next; 151  } 152     return flag; 153 } 154 
155 //刪除元素爲value的第一個元素
156 bool deleteData_link(Link* link, T value) 157 { 158     Node* node = link->next; 159     for(int i = 0; node != NULL; i++) 160  { 161         if(node->data == value) 162             //做爲是否刪除成功的一個標誌
163             return delete_link(link, i); 164         node = node->next; 165  } 166     return false; 167 } 168 
169 //查找元素value的下標
170 int indexOf_link(Link* link, T value) 171 { 172     Node* node = link->next; 173     for(int i = 0; node != NULL; i++) 174  { 175         if(node->data == value) 176             return i; 177         node = node->next; 178  } 179     return -1; 180 } 181 
182 //遍歷鏈表
183 void travel_link(Link* link) 184 { 185     Node* node = link->next; 186     while(node != NULL) 187  { 188         printf("%d ",node->data); 189         node = node->next; 190  } 191     puts(""); 192 } 193 
194 //鏈表逆序
195 void reverse(Link link) 196 { 197     if(link == NULL || link->next == NULL) 198         return; 199     //0、記錄前一個節點與當前節點
200     Node* prevNode = link->next; 201     Node* node = prevNode->next;//NULL 202     //只要當前節點存在
203     while(node != NULL) 204  { 205         //一、先記錄當前節點的後一個節點
206         Node* nextNode = node->next; 207         //二、讓當前節點(node)的下一個節點(node->next)指向(=)前一個節點(prev)
208         node->next = prevNode; 209         //三、讓前一個節點指向當前節點、當前節點指向原先記錄的下一個節點
210         prevNode = node; 211         node = nextNode; 212  } 213     //四、讓原來的第一個元素變爲尾元素,尾元素的下一個置NULL
214     link->next->next = NULL; 215     //五、讓鏈表的頭節點指向原來的尾元素
216     link->next = prevNode; 217 } 218 
219 //鏈表中每k個節點進行翻轉,若最後一組節點數量不足k個,則按實際個數翻轉。
220 void reverseByNum(Node* prev,Node* node,int num) 221 { 222     if(node == NULL) 223         return; 224     Node* prevNode = node; 225     Node* curNode = node->next; 226     int count = 1; 227     while(curNode != NULL) 228  { 229         Node* nextNode = curNode->next; 230         curNode->next = prevNode; 231         prevNode = curNode; 232         curNode = nextNode; 233         count++; 234         if(count == num) 235  { 236             Node* tmp = prev->next; 237             prev->next->next = curNode; 238             prev->next = prevNode; 239  reverseByNum(tmp,curNode,num); 240             return; 241  } 242  } 243     prev->next->next = curNode; 244     prev->next = prevNode; 245 } 246 
247 void reverses(Link link,int num) 248 { 249     Node *node = link->next; 250  reverseByNum(link,node,num); 251 }
View Code(思路2)

思路1:該題能夠經過數組來實現要求,按照題意將數組分割並分別翻轉便可。同時要考慮到數組沒法均分的狀況。優化

思路2:經過鏈表實現,詳見博客第三章節:[C語言]單向鏈表的構建以及翻轉算法編碼

總結:該題很簡單,留意數組沒法均分的狀況便可。

 


 

第三題(已優化):

輸入一個由大寫字母‘A-Z’組成的字符串,按照以下方式,對字符串中的字符進行編碼:
1.統計每一個字符出現的次數,並根據出現次數對字符進行權重分配;
a.出現次數越高,權重越大; b.出現次數相同,字符值越小,權重越大; c.權重值爲1~26,必須從1開始,連續分配,數值越大,權重越高;
2.把權重最小的兩個字符構成二叉樹的左右子節點,其和做爲根節點(節點值爲字符權重);
a.若兩個子節點值不等,較小值做爲左子節點;
b.若兩個子節點值相同(多字符的權重和與另外一個字符權重可能相同),則葉子節點做爲左子節點;
3.重複過程2,直到根節點值爲全部字符的權重和;
4.將樹的左邊定位0,右邊定位1,從根節點到字符節點的路徑,即爲其編碼值;
示例:
1.輸入字符串‘MBCEMAMCBA’,各字符出現次數分別爲M:3,A:2,B:2,C:2,E:1;
2.根據字符出現次數和字符大小,進行排序,結果爲:M>A>B>C>E,對應權重值爲 M:5,A:4,B:3,C:2,E:1
3.根據規則生成權重樹:
a.(M:5,A:4,B:3,C:2,E:1)中E:1和C:2值最小,相加得3,則E:1爲左節點,C:2爲右節點,3爲根節點;
b.(M:5,A:4,B:3,3)中B:3和3值最小,相加得6,則B:3爲左節點,3爲右節點,6爲根節點;
c.(M:5,A:4,6)中M:5和A:4值最小,相加得9,則A:4爲左節點,M:5爲右節點,9爲根節點;
d.(6,9)中只有兩個值,相加得15,則6爲左節點,9爲右節點,15爲根節點;
e.根節點達到全部字符的權重和1+2+3+4+5=15,結果以下:
               15
           0/     1\
         6            9
      0/ 1\       0/ 1\
   B:3      3   A:4   M:5
           0/ 1\
         E:1   C:2

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 typedef struct Node  5 {  6     char ch;  7     char code;  8     int count;  9     int weight;  10     struct Node* left;  11     struct Node* right;  12 }Node;  13 
 14 Node* create_node(void)  15 {  16     Node* node = malloc(sizeof(Node));  17     node->ch = 0;  18     node->weight = 0;  19     node->left = NULL;  20     node->right = NULL;  21 }  22 
 23 int ch_cnt = 0;  24 char arr_code[10000] = {};  25 Node arr_node[26] = {};  26 
 27 void count_weight(char* str)  28 {  29     for(int i=0,j=0; str[i]; i++)  30  {  31         for(j=0; j<ch_cnt; j++)  32  {  33             if(str[i] == arr_node[j].ch) break;  34  }  35 
 36         if(j<ch_cnt) continue;  37         arr_node[ch_cnt++].ch = str[i];  38  }  39 
 40     for(int i=0; i<ch_cnt; i++)  41  {  42         for(int j=0; str[j]; j++)  43  {  44             if(arr_node[i].ch == str[j]) arr_node[i].count++;  45  }  46  }  47 
 48     for(int i=0; i<ch_cnt-1; i++)  49  {  50         for(int j=i+1; j<ch_cnt; j++)  51  {  52             if(arr_node[i].count > arr_node[j].count ||
 53                 (arr_node[i].count==arr_node[j].count && arr_node[i].ch < arr_node[j].ch))  54  {  55                 Node t = arr_node[i];  56                 arr_node[i] = arr_node[j];  57                 arr_node[j] = t;  58  }  59  }  60  }  61 
 62     for(int i=0; i<ch_cnt; i++)  63  {  64         arr_node[i].weight = i+1;  65  }  66 }  67 
 68 void create_tree(void)  69 {  70     if(ch_cnt<=1) return;  71 
 72     Node* root = create_node();  73     root->left = create_node();  74     root->right = create_node();  75 
 76     *(root->left) = arr_node[0];  77     *(root->right) = arr_node[1];  78 
 79     root->left->code = '0';  80     root->right->code = '1';  81 
 82     root->weight += root->left->weight;  83     root->weight += root->right->weight;  84     
 85 
 86     arr_node[1] = *root;  87 
 88     for(int i=0; i<ch_cnt-1; i++)  89  {  90         arr_node[i] = arr_node[i+1];  91  }  92 
 93     ch_cnt--;  94 
 95     for(int i=0; i<ch_cnt-1; i++)  96  {  97         for(int j=i+1; j<ch_cnt; j++)  98  {  99             if(arr_node[i].weight > arr_node[j].weight ||
100                 (arr_node[i].weight == arr_node[j].weight&&!arr_node[i].ch)) 101  { 102                 Node t = arr_node[i]; 103                 arr_node[i] = arr_node[j]; 104                 arr_node[j] = t; 105  } 106  } 107  } 108  create_tree(); 109 } 110 void show_tree(Node* tree) 111 { 112     if(NULL == tree) return; 113     show_tree(tree->left); 114     show_tree(tree->right); 115 } 116 
117 int find_tree(Node* tree,char ch) 118 { 119     if(NULL == tree) return 0; 120     if(tree->ch == ch) 121  { 122         arr_code[ch_cnt++] = tree->code; 123         return 1; 124  } 125 
126     if(find_tree(tree->left,ch) || find_tree(tree->right,ch)) 127  { 128         arr_code[ch_cnt++] = tree->code; 129  } 130 } 131 
132 int main() 133 { 134     int t = 0; 135     scanf("%d",&t); 136     char str[t][1000]; 137     for(int i=0; i<t; i++) 138  { 139  gets(str[i]); 140  } 141     for(int i=0; i<t; i++) 142  { 143  count_weight(str[i]); 144  create_tree(); 145         for(int j=0; str[i][j]; j++) 146  { 147             ch_cnt = 0; 148  find_tree(arr_node,str[i][j]); 149             for(int k=ch_cnt-1; k>=0; k--) 150  { 151                 printf("%c",arr_code[k]); 152  } 153  } 154  } 155 
156 }
View Code(思路二)

方向:此題與哈夫曼樹相關(哈夫曼樹:https://blog.csdn.net/move_now/article/details/53398753)

思路一:以哈夫曼樹爲主體,在此基礎上添加對字符串中各個字符分配權重的功能,最後分解字符串,根據各個字符的權重依次輸出路徑。

思路二:以每類字符爲主體,建立儲存各種字符信息的結構體,計算出各個字符的權重,延伸出兩個空子葉,在此基礎上根據各個字符的權重、按照題目規則將其鏈接成哈夫曼樹形結構,最後分解字符串,根據各個字符的權重依次輸出路徑。

總結:總的來講,思路一是在現有哈夫曼樹框架下進行代碼的修改、添加,輪子已經造好,咱們直接拿來用便可,能極大地減小實際代碼量,但修改現有哈夫曼樹代碼時容易打亂自身思路且缺乏創造性;思路二是以每類字符爲主體,能在編寫其結構體時有效的整理思路,整個程序關聯性強,富有創造力,但程序難度較大。

PS :該程序本地測試無誤,但上傳後一直爲0分,未能查明緣由。

 


 

第四題(未優化):

  實現find_sub_string(str1,str2)函數,判斷字符串str2在str1中出現的次數。返回str2在str1中出現的次數。

int find_sub_string(const std::string& str1, const string& str2);

 1 #include <stdio.h>
 2 #include <string.h>
 3 
 4 int find_sub_string(char* str1, char* str2)  5 {  6     int count = 0,i2 = 0;  7     if(*str2 && *str1)  8  {  9             for(int i=0; *(str1+strlen(str2)+i-1); i++) 10  { 11                     for(int j=i; *(str1+j); j++) 12  { 13                             if(*(str1+j) == *(str2+i2)) 14  { 15                                if(strlen(str2)-1 == i2) 16  { 17                         count++; 18                         i2 = 0; 19                         break; 20  } 21                     else i2++; 22  } 23                 else 
24  { 25                     i2 = 0; 26                     break; 27  } 28  } 29  } 30  } 31     else  return count; 32 } 33 
34 int main() 35 { 36     int t; 37     scanf("%d",&t); 38     int x = t; 39     int a[t]; 40 
41     while(x--) 42  { 43         char str1[10][1000] = {}; 44         char str2[10][1000] = {}; 45         scanf("%s",str1[x]); 46         scanf("%s",str2[x]); 47         printf("%d\n",find_sub_string(str1[x], str2[x])); 48  } 49 }        
View Code

思路:思路簡單,循環嵌套。

總結:該題可利用庫函數實現。

 


 

第五題:

有一個吃金幣遊戲:
1.地圖中有N個城堡(編號分別爲0~N-1),每一個城堡中掛着一面旗子;
2.某些城堡之間是連通的,在其連通的路上,分散着若干個金幣(個數可能相同,也可能不一樣);
3.玩家走過存在金幣的路以後,能夠得到這條路上的全部金幣,11同一條路走屢次,只有第一次可得到金幣;

遊戲規則:
1.玩家能夠從任意一個城堡出發;
2.玩家必須拿到全部城堡的旗子;
3.玩家走過的全部路,不能存在環路;
4.必定存在至少一條能讓玩家拿到全部旗子的路線;

請設計一個算法,計算在遵照以上游戲規則的的前提下,最多能獲取到的金幣個數。

補充規則中對環路的說明:
一、環路就是最終走過的路徑中存在圈,實例以下:
非環路: 環路:1-2-5-4-1則成爲環路
1----2 3 1----2----3
| | | |
| | | |
4----5----6 4----5----6
| | | | |
| | | | |
7 8 9 7 8----9

二、如說明1中的路徑,玩家走1-2-5-4-7-4-5,雖然無圈,可是4-七、5-4中的路徑金幣只能吃一次,重複走第二次金幣不能夠獲取

 


 

第六題(未優化):

  在H.264視頻編碼標準中,編碼幀由NALU頭和NALU主體組成,其中NALU頭由一個字節組成。在實際編碼時,在每一個NAL前添加起始碼 0x000001,解碼器在碼流中檢測到起始碼,當前NAL結束。
  爲了防止NAL內部出現0x000001的數據,在編碼完一個NAL時,若是檢測出有連續兩個0x00字節,就在後面插入一個0x03。
  當解碼器在NAL內部檢測到0x000003的數據,就把0x03拋棄,恢復原始數據。給定一組包含SPS NALU的編碼數據,找出解碼後的SPS數據。好比:
  輸入:{0x1f 0x00 0x00 0x01 0x67 0x42 0xd0 0x80 0x00 0x00 0x03 0x00 0x80 0x00 0x0f 0x00 0x00 0x01 0x68 0xce 0x3c 0x80},
  處理:在上述例子中,第一個0x00 0x00 0x01爲識別到的數據頭,0x00 0x00 0x03 0x00數據中,0x03爲需拋棄數據,第二個0x00 0x00 0x01爲下一個數據頭,那麼取出兩個數據頭中間的數據而且拋棄掉此0x03,結果以下:{0x67 0x42 0xd0 0x80 0x00 0x00 0x00 0x80 0x00 0x0f }。

 1 #include <stdio.h>
 2 #include <string.h>
 3 
 4 void find_sps_in_h264(unsigned int* num, int len)  5 {  6     unsigned int n[50] = {};  7     for(int i=2; i<len; i++)  8  {  9         if(num[i-2]==0x00 && num[i-1]==0x00 && num[i]== 0x01) 10  { 11             for(int j=2; i<len-1; j++) 12  { 13                 n[j] = num[++i]; 14                 if(j>=4 && n[j-2]==0x00 && n[j-1]==0x00 && n[j]== 0x01) 15  { 16                     for(int k=2; k<j-2; k++) 17  { 18                         if(k>=4 && n[k-2]==0x00 && n[k-1]==0x00 && n[k]== 0x03) 19  { 20                             continue; 21  } 22                         else printf("%x ",n[k]); 23  } 24                     puts(""); 25                     return; 26  } 27                 else if(i == len-1) 28  { 29                     for(int k=2; k<=j; k++) 30  { 31                         if(k>=4 && n[k-2]==0x00 && n[k-1]==0x00 && n[k]== 0x03) 32  { 33                             continue; 34  } 35                         else printf("%x ",n[k]); 36  } 37                     puts(""); 38                     return; 39  } 40  } 41  } 42  } 43 } 44 
45 int main() 46 { 47     int t; 48     scanf("%d",&t); 49 
50     int len; 51     unsigned int num[51] = {}; 52     for(int i=0; i<t; i++) 53  { 54         scanf("%d",&len); 55         if(len<7) len = 7; 56         else if(len>50) len =50; 57         for (int j=0; j<len; j++) 58  { 59             scanf("%x",&num[j]); 60  } 61  find_sps_in_h264(num,len); 62  } 63     return 0; 64 }
View Code

思路:經過識別編碼「0x00 0x00 0x01」從碼流中取出兩個數據頭中間的數據,再將數據中「0x00 0x00 0x03」中的編碼「0x03」去除。

總結:能夠將須要重複使用的功能模塊進行函數封裝,優化代碼,提升代碼簡潔性與可閱讀性。如:斷定數據頭的功能模塊。

 


 

第七題(已優化):

  給定一個全小寫的英文字符串,請在該字符串中找到一個連續子字符串,使得子字符串沒有重複的字符而且長度最長,計算此最長字符串的長度。好比:abcbdeab,最長的子字符串爲cbdea,長度爲5;aaaa,最長子字串爲a,長度爲1。

 1 #include <stdio.h>
 2 
 3 int longest_substr(char* str)  4 {  5     int longest = 0;  6     for(int i=0,j=0; str[i]; i++)  7  {  8         for(j=i+1; str[j]; j++)  9  { 10             int flag = 0; 11             for(int k=j-1; k>=i; k--) 12  { 13                 if(str[j] == str[k]) flag = 1; 14  } 15 
16             if(flag) break; 17  } 18         int len = j - i; 19         if(len > longest) longest = len; 20  } 21     return longest; 22 } 23 
24 int main() 25 { 26     int n = 0; 27     scanf("%d",&n); 28     char str[n][101]; 29     
30     for(int i=0; i<n; i++) 31  { 32         stdin->_IO_read_ptr = stdin->_IO_read_end; 33  gets(str[i]); 34  } 35 
36     for(int i=0; i<n; i++) 37  { 38         printf("%d\n",longest_substr(str[i])); 39  } 40 }
View Code

思路:思路簡單,循環嵌套。

總結:三層for循環嵌套之間的關係要理清。

 


 

第八題(已優化):

  一個數能夠用二進制表示,也能夠用十進制表示,若是該數的二進制表示法全部位數字之和等於十進制表示法全部位數字之和,則稱該數爲神奇數。好比:21(十進制)=10101(二進制),全部位數之和爲2+1=3,1+0+1+0+1=3。求小於等於M的神奇數有多少個。

 1 #include <stdio.h>
 2 
 3 int is_magical(int num)  4 {  5     int sum1 = 0;  6     for(int i=0; i<32; i++)  7  {  8         sum1 += (num>>i)&1;  9  } 10 
11     int sum2 = 0; 12     while(num) 13  { 14         sum2 += num%10; 15         num /= 10; 16  } 17 
18     return sum1 == sum2; 19 } 20 
21 int main() 22 { 23     int cnt = 0; 24     scanf("%d",&cnt); 25     int m[cnt]; 26 
27     for(int i=0; i<cnt; i++) 28  { 29         scanf("%d",&m[i]); 30  } 31 
32     for(int i=0; i<cnt; i++) 33  { 34         int n = 0; 35         for(int j=1; j<=m[i]; j++) 36  { 37             is_magical(j) && n++; 38  } 39         printf("%d\n",n); 40  } 41 }
View Code

思路:思路簡單,考點主要在於對二進制數據的應用。

總結:二進制全部位數之和可以使用用語句 for(int i=0; i<32; i++)  sum1 += (num>>i)&1; 計算。

 

 


 

第九題(未優化):

  咱們來玩一個大富翁的遊戲,在地圖上有N個連續的城市,城市對某件商品的售價爲[V1,V2,V3...VN],你做爲將來的大富翁看到其中的商機,打起了倒賣商品賺取差價的主意。約束條件:你只能順序從第一個城市出發,不能走回頭路,每次只能交易一件商品,再下次買入商品後必須賣掉以前買入的商品,求你能賺取的最大財富。好比:城市商品售價爲[1,9,2,3,8],最大財富爲(9-1)+(8-2)=14;城市商品售價爲[9,8,3,2,1],最大財富爲0,由於你買啥都沒法賺錢。

 1 #include <stdio.h>
 2 #include <string.h>
 3 
 4 int min;  5 int max;  6 int a;  7 
 8 int x(int* val)  9 { 10     int sum = 0; 11     int i = 0; 12     int m = max, n = min; 13     while(val[i]) 14  { 15         if(val[i] < val[i+1]) 16  { 17             min = i++; 18             while(val[i] < val[i+1] && val[i]) 19  { 20                 i++; 21  } 22                 max = i++; 23                 sum += val[max]-val[min]; 24  } 25         else i++; 26  } 27     return sum; 28 } 29 
30 int main() 31 { 32     int t; 33     scanf("%d",&t); 34 
35     int val[10][100] = {}; 36     for(int i=0; i<t; i++) 37  { 38         scanf("%d",&a); 39         for (int j=0; j<a; j++) 40  { 41             scanf("%d",&val[i][j]); 42  } 43  } 44     for(int i=0; i<t; i++) 45  { 46         printf("%d\n",x(val[i])); 47  } 48 }
View Code(思路二)

思路一:直接比較當前城市售價與下一城市售價,若下一城市售價高於當前城市售價,則對兩者的差值進行累加,遍歷城市後便可得到最大財富。

思路二:尋找不一樣城市售價的「拐點」,遍歷城市將全部彼此鄰近的「最高拐點」與「最低拐點」的差值進行累加,便可得到最大財富。

總結:總的來講,思路一簡單粗暴,代碼簡單、極易實現,但相比思路二會進行更多的加法運算;思路二理論上算法更優,但在該題中沒法體現其優點。

 


 

第十題(已優化):

假設你站在一棵二叉樹的右邊,從上往下,請輸出你看到的節點。好比:
       5 <---
      / \
    2    3 <---
  /      / \
4      6    8 <---
返回 538。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 static int index = 0;  5 
 6 typedef struct Node  7 {  8     char ch;  9     struct Node* left; 10     struct Node* right; 11 }Node; 12 
13 Node* create_node(char ch) 14 { 15     Node* node = malloc(sizeof(Node)); 16     node->ch = ch; 17     node->left = NULL; 18     node->right = NULL; 19 } 20 
21 void create_tree(Node** tree,char* str) 22 { 23     if('\0'==str[index]) return; 24     
25     if(str[index] == '#') 26  { 27         *tree = NULL; 28         return; 29  } 30     *tree = create_node(str[index]); 31     if(str[index+1]) 32  { 33         index++; 34         create_tree(&(*tree)->left,str); 35  } 36 
37     if(str[index+1]) 38  { 39         index++; 40         create_tree(&(*tree)->right,str); 41  } 42 } 43 
44 void show_tree(Node* tree) 45 { 46     if(NULL == tree) return; 47     printf("%c\n",tree->ch); 48     show_tree(tree->right); 49 } 50 
51 int main() 52 { 53     int t = 0; 54     scanf("%d",&t); 55     char str[t][1000]; 56     for(int i=0; i<t; i++) 57  { 58  gets(str[i]); 59  } 60     for(int i=0; i<t; i++) 61  { 62         index = 0; 63         Node* tree = NULL; 64         create_tree(&tree,str[i]); 65  show_tree(tree); 66  } 67 }
View Code

思路:思路簡單,考點主要在於構建二叉樹。

總結:該題有一個小坑,多心的解題人可能會考慮到:若上圖中的6存在子葉x,那麼「從上往下、從右往左」看的時候是否會「看」到x?若將這種可能性考慮進去,代碼的複雜程度提升數十倍的同時會致使該題考察點不明確,考察者沒有這麼作的意義。實際上這種可能性不屬於該題的考察點,考慮過多反而容易誤解題意。

 


 

實現效果:

相關文章
相關標籤/搜索