中等
使用方法
无重复字符的最长字串—滑动窗口
给定一个字符串s,找出其中不含有重复字符的最长字串的长度。(连续的)
int lengthOfLongestSubstring(char * s){int res = 0;int len = strlen(s);/* 存储 ASCII 字符在子串中出现的次数 */int freq[256] = {0};/* 定义滑动窗口为 s[l...r] */int l = 0, r = -1;while (l < len) {/* freq 中不存在该字符,右边界右移,并将该字符出现的次数记录在 freq 中 */if (r < len - 1 && freq[s[r + 1]] == 0) {freq[s[++r]]++;/* 右边界无法拓展,左边界右移,刨除重复元素,并将此时左边界对应的字符出现的次数在 freq 的记录中减一 */} else {freq[s[l++]]--;}/* 当前子串的长度和已找到的最长子串的长度取最大值 */res = fmax(res, r - l + 1);}return res;}
- 滑动窗口,“窗口”内存的数子串不一定是按照原字符串那样存
- strlen(str),求字符串的长度
- 字符作为数组下标,可
- fmax(a, b),求出两个数的最大值
正则匹配—动态规划

注意,’‘匹配的意思是:前面的那个字母被匹配的次数是0次或多次,而不是自己匹配的,要与前面的一个字母一起匹配。’.*’可以匹配任意字符串
使用动态规划,定义一个状态存储器dp[][],dp[i][j]表示的是s[i]与p[j]的匹配情况,与其前面的匹配情况有关。再定义状态转移方程。m为s的长度,n为p的长度,则sp[m][n]表示最终的匹配结果。
此外,为了考虑边界情况,令dp的规模为[m+1][n+1],设dp[0][0]为true,即两个长度为0时是匹配的,然后按照上图给dp赋值时,都要给dp的i与j加一,最后dp[m+1][n+1]表示最后结果。 又,单独考虑dp的第零行的情况,如果p[j]==’‘,则dp[0][j+1]=dp[0][j-1],就考虑成,s为空时,p有字母与’‘,然后 *将其前的字母匹配0次。
/*** @param {string} s* @param {string} p* @return {boolean}*/var isMatch = function(s, p) {// 动态规划var m = s.length, n = p.length;var dp = [];for (let i in [...Array(m+1).keys()]){dp[i] = [];for(let j in [...Array(n+1).keys()]){dp[i][j] = false;}}dp[0][0] = true;for (let j = 0; j < n; j++){if(p[j] === '*'){dp[0][j+1] = dp[0][j-1];}}for (let i = 0; i< m; i++){for(let j = 0; j < n; j++){if(s[i] === p[j] || p[j] === '.'){dp[i+1][j+1] = dp[i][j];}else if(s[i] !== p[j] && p[j] != '*'){dp[i+1][j+1] = false;}else if(p[j] === '*'){if(s[i] === p[j-1] || p[j-1] === '.'){dp[i+1][j+1] = dp[i+1][j] || dp[i][j+1] || dp[i+1][j-1];}else {dp[i+1][j+1] = dp[i+1][j-1];}}}}return dp[m][n]; // 最后是在上面跳出循环的结果};
盛最多水的容器—双指针

容积就是 两个数之间的距离 乘以 两者间较小的数值。
我自己写的代码:5%
/*** @param {number[]} height* @return {number}*/var maxArea = function(height) {let ob = [], n = height.length, maxS = 0, tmp = 0;for (let i = 0; i < n; i++){ob[i] = {};ob[i].ind = i;ob[i].val = height[i];}ob.sort((x, y) => {return y.val - x.val;});for (let i = 0 ; i < n-1; i++){let ran = Math.pow(n, 0.6);for (let j = i+1; j<n; j++){if(ran <= 0) break;tmp = (Math.abs(ob[i].ind - ob[j].ind)) * ob[j].val;if(tmp > maxS){maxS = tmp;}else ran--;}}return maxS;};
解析的,用双指针,一个从数组左、一个从数组右开始,每次计算两个的容积,再向中间移动较小值处的指针。
三数之和 — 双指针
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
如:
输入:nums = [-1,0,1,2,-1,-4]输出:[[-1,-1,2],[-1,0,1]]
我想的是,如下:
/*** @param {number[]} nums* @return {number[][]}*/var threeSum = function(nums) {var results = [], flag = 0, rn = 0;nums = nums.sort(sortNumber);// 先排序,再去除多余的重复数字for (var k = 0; k < nums.length-1; k++) {flag = 0;for (var m = k+1; m < nums.length; m++){if (nums[k] == nums[m]) {flag++;}else {if (flag > 2 && nums[k] == 0){nums.splice(k+3, flag-2);flag = 0;break;}else if (flag > 1 && nums[k] != 0){nums.splice(k+2, flag-1);flag = 0;break;}}}// nums数组的最后有一些重复的数字if (m == nums.length && flag > 1) {if (nums[k] == 0 && flag > 2) {nums.splice(k+3, flag-2);}else if(nums[k] != 0) {nums.splice(k+2, flag-1);}}}// 收集三元组for (var k = 0; k < nums.length-2 && nums[k] <= 0; k++){for (var i = k+1; i < nums.length-1; i++) {for (var j = i+1; j < nums.length; j++) {if (nums[i] + nums[k] + nums[j] === 0){results[rn++] = [nums[k], nums[i], nums[j]].sort(sortNumber);break;}}}}results = results.sort(sortNumber);// 去除掉重复的三元组for (i = 0; i < results.length-1; i++) {for (j = i+1; j < results.length; j++) {flag = 0;for (k = 0; k < 3; k++){if (results[i][k] == results[j][k]){flag++;}}if(flag == 3) {results.splice(j,1);j--; // 为什么不加这个就不能去掉最后一个子数组呢?}}}return results;};// 针对负数的排序function sortNumber(a, b) {return a - b;}
最接近的三数之和 — 双指针
给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。3<=n<=1000。
返回这三个数的和。
假定每组输入只存在恰好一个解。
我自己也想到了双指针,但是写的时候前面还好,中间有一个判断的地方没想到,想复杂了。下面是查看方法后改的,只在我写的基础上改了中间的if-else if -else
/*** @param {number[]} nums* @param {number} target* @return {number}*/var threeSumClosest = function(nums, target) {if(nums.length < 3) return;var res = nums[0] + nums[1] + nums[2], n = nums.length;nums = nums.sort(sortNumber); // 排序for (var i = 0; i < n-2; i++){var j = i+1, p = n-1;while(j < p){var tmp = nums[i] + nums[j] + nums[p];var tmp_res = Math.abs(tmp-target);if(tmp_res < Math.abs(res - target)){res = tmp;}if(tmp > target)p--;else if(tmp < target)j++;elsereturn target}}return res;};function sortNumber(a, b) {return a - b;}
时间复杂度 O(n2)
找规则
Z字形变换
实际是N字型变换,给定一个字符串s和一个行数numRows,以从上往下、从左往右进行N字形排列。
比如输入字符串PAYPALISHIRING行数为3,则排列如下:
P A H NA P L S I I GY I R
则对应输出为PAHNAPLSIIGYIR,按每行输出。
实际是找字符串s中的每个字符的下标与排列中位置所在的行的关系
查看的一个解说才写出的代码:
/*** @param {string} s* @param {number} numRows* @return {string}*/var convert = function(s, numRows) {let strings = [[]], f = 2*numRows-2;if(numRows == 0) return '';if(numRows == 1) return s;for (let i = 0; i < s.length; i++){let tmp = i % f;if(i < numRows){strings[i] = s[i];}else {if(tmp < numRows){strings[tmp] += s[i];} else {strings[Math.abs(f-tmp)] += s[i];}}}let result = '';for (let i of strings){result += i;}return result;};
