移除重复项
public int removeDuplicates(int[] nums) {
int left = 0, right = 0;
while (right < nums.length) {
if (nums[left] == nums[right]) {
right++;
//找到不重复的元素
} else {
nums[left+1] = nums[right];
left++;
}
}
return left + 1;
}
删除指定元素
public int removeElement(int[] nums, int val) {
int right = nums.length - 1, left = 0;
while (left <= right) {
if (nums[left] != val) {
left++;
//找到相等的就和不相等的交换
} else {
nums[left] = nums[right];
right--;
}
}
return right + 1;
}
KMP
//这种写法next数组表示的当前子串的最长公共前后缀长度,字符串下标从0开始
public int strStr(String haystack, String needle) {
char[] chars = haystack.toCharArray();
char[] chars1 = needle.toCharArray();
int[] next = new int[chars1.length];
//计算next数组
//前缀终止位置-1
int prefix = 0;
next[0] = prefix;
//后缀终止位置-1
for (int suffix = 1; suffix < next.length ; suffix++) {
//前后缀末尾不相同的情况,就要向前回溯,直到前后缀结尾一样或prefix为0
//回溯的位置是前缀结尾的前一位的next数组值
//例如字符串aaabbab prefix = 2 suffix = 3时不相等时就看prefix的前一位的next数组值,
//prefix = 1时aa的最长前后缀长度是2,不过前缀aa结尾的a和后缀ab结尾的b不相等还要继续回退
//prefix = 0可以结束回退,next[3]为0
//因为prefix的前一位的next数组值记录着prefix的前一位的相同前后缀的长度
while (prefix > 0 && chars1[prefix] != chars1[suffix]) {
prefix = next[prefix-1];
}
//前后缀末尾相同就继续往后找直到前后缀结尾不一样
if (chars1[prefix] == chars1[suffix]) {
prefix++;
}
next[suffix] = prefix;
}
int b = 0;
for (int a = 0; a < haystack.length(); a++) {
//不匹配就回退
while (b > 0 && chars[a] != chars1[b]) {
//因为next存的是数组长度,所以这里刚好是回退到已匹配的后一位
b = next[b-1];
}
if (chars[a] == chars1[b]) {
b++;
}
if (b == chars1.length) {
return a - needle.length() + 1;
}
}
return -1;
}
//这种写法next数组的意思当前字符的前面字符的最长公共前后缀长度+1,字符串下标从1开始,下标0为空字符
public int strStr(String haystack, String needle) {
if (needle.length() == 0) {
return 0;
}
haystack = " " + haystack;
needle = " " + needle;
char[] pattern = needle.toCharArray();
char[] source = haystack.toCharArray();
int[] next = new int[pattern.length];
Arrays.fill(next,1);
int pre = 1;
int suffix = 2;
while (suffix < next.length - 1) {
while (pre > 1 && pattern[pre] != pattern[suffix]) {
pre = next[pre];
}
if (pattern[pre] == pattern[suffix]) {
next[++suffix] = ++pre;
continue;
}
suffix++;
}
int a = 1, b = 1;
while (a < source.length) {
if (source[a] == pattern[b]) {
a++;
b++;
if (b == pattern.length) {
return a - pattern.length;
}
}
while (a < source.length && source[a] != pattern[b]) {
if (b > 1) {
b = next[b];
} else {
a++;
}
}
}
return -1;
}
移动零
public void moveZeroes(int[] nums) {
if (nums.length < 2) {
return;
}
int zero = 0, notZero = 0;
while (notZero < nums.length) {
if (nums[notZero] != 0) {
int temp = nums[zero];
nums[zero] = nums[notZero];
nums[notZero] = temp;
notZero++;
zero++;
} else {
notZero++;
}
}
}
反转字符串中的单词 III
public String reverseWords(String s) {
String trim = s.trim();
String[] s1 = trim.split(" ");
StringBuilder sb = new StringBuilder();
for (String s2 : s1) {
char[] chars = s2.toCharArray();
int left = 0, right = s2.length() - 1;
while (left < right) {
char temp = chars[left];
chars[left] = chars[right];
chars[right] = temp;
left++;
right--;
}
sb.append(chars);
sb.append(" ");
}
sb.deleteCharAt(sb.length()-1);
return sb.toString();
}
验证回文串||
public boolean validPalindrome(String s) {
char[] chars = s.toCharArray();
int left = 0, right = chars.length - 1;
while (left < right) {
if (chars[left] != chars[right]) {
return isPalindrome(chars, left + 1, right) || isPalindrome(chars, left, right - 1);
}
left++;
right--;
}
return true;
}
public boolean isPalindrome(char[] s, int left, int right) {
while (left < right) {
if (s[left] != s[right]) {
return false;
}
left++;
right--;
}
return true;
}
盛最多水的容器
/**
* 双指针的遍历方法,相当于找的是以每个点为端点的图形的最大面积,那么就一定包含了整个问题的最大面积
* 假设状态 S(i, j)S(i,j) 下 h[i] < h[j]h[i]<h[j] ,在向内移动短板至 S(i + 1, j)S(i+1,j) ,
* 则相当于消去了 {S(i, j - 1), S(i, j - 2), ... , S(i, i + 1)}S(i,j−1),S(i,j−2),...,S(i,i+1) 状态集合。
* 而所有消去状态的面积一定都小于当前面积(即 < S(i, j)<S(i,j)),因为这些状态:
* 短板高度:相比 S(i, j)S(i,j) 相同或更短(即h[i]≤h[i] );不可能比短板的长,因为最短的板在左边
* 底边宽度:相比 S(i, j)S(i,j) 更短;
*/
public int maxArea(int[] height) {
int left = 0, right = height.length - 1;
int res = 0;
while (left < right) {
int h = Math.min(height[left], height[right]);
res = Math.max((right - left) * h,res);
if (height[left] < height[right]) {
left++;
} else {
right--;
}
}
return res;
}
下一个更大排序
/**
* 我们希望下一个数比当前数大,这样才满足“下一个排列”的定义。因此只需要将后面的「大数」与前面的「小数」交换,
* 就能得到一个更大的数。比如 123456,将 5 和 6 交换就能得到一个更大的数 123465。
* 我们还希望下一个数增加的幅度尽可能的小,这样才满足“下一个排列与当前排列紧邻“的要求。为了满足这个要求,我们需要:
* 在尽可能靠右的低位进行交换,需要从后向前查找
* 将一个 尽可能小的「大数」 与前面的「小数」交换。比如 123465,下一个排列应该把 5 和 4 交换而不是把 6 和 4 交换
* 将「大数」换到前面后,需要将「大数」后面的所有数重置为升序,升序排列就是最小的排列。
* 以 123465 为例:首先按照上一步,交换 5 和 4,得到 123564;然后需要将 5 之后的数重置为升序,
* 得到 123546。显然 123546 比 123564 更小,123546 就是 123465 的下一个排列
*/
public void nextPermutation(int[] nums) {
//例如12385764
for (int i = nums.length - 1; i > 0; i--) {
//找到【5,7】是升序的
if (nums[i-1] < nums[i]) {
int temp = nums[i-1];
for (int j = nums.length - 1; j >= i; j--) {
//找到6比5大,交换5和6变成12386754
if (nums[j] > temp) {
nums[i-1] = nums[j];
nums[j] = temp;
//对754进行升序排序变成12386457
Arrays.sort(nums,i,nums.length);
return;
}
}
}
}
Arrays.sort(nums);
}
颜色分类
public void sortColors(int[] nums) {
int lt = 0, gt = nums.length - 1, equal = 0;
int base = 1;
while (equal <= gt) {
//这步执行equal位置肯定是1,lt位置肯定是0,equal位置不可能是2因为是2的话会被移到最右边
if (nums[equal] < base) {
swap(nums,lt,equal);
lt++;
equal++;
} else if (nums[equal] == base) {
equal++;
//不确定交换后equal位置的是不是等于1所以equal不加1,equal位置有可能是0,1,2
} else {
swap(nums,gt,equal);
gt--;
}
}
}
反转字符串里的单词
public String reverseWords(String s) {
Deque<String> stack = new LinkedList<>();
String trim = s.trim();
char[] chars = s.toCharArray();
int i = 0;
while (i < chars.length) {
//找到单词首字符
if (chars[i] != ' ') {
int start = i;
//直到单词尾字符的后一位
while (i < chars.length && chars[i] != ' ') {
i++;
}
int end = i;
stack.push(s.substring(start,end));
}
i++;
}
StringBuffer sb = new StringBuffer();
while (!stack.isEmpty()) {
sb.append(stack.pop());
sb.append(" ");
}
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
}
轮转数组
ublic void rotate(int[] nums, int k) {
int length = nums.length;
k = k % length;
reverse(nums,0,length - 1);
reverse(nums,0,k - 1);
reverse(nums,k,length - 1);
}
public void reverse(int[] nums, int left, int right) {
while (left < right) {
swap(nums,left,right);
left++;
right--;
}
}
public void swap(int[] nums, int a, int b) {
int temp = nums[a];
nums[a] = nums[b];
nums[b] = temp;
}
接雨水
public int trap(int[] height) {
int sum = 0;
int[] maxLeft = new int[height.length];
int[] maxRight = new int[height.length];
for (int i = 1; i < height.length; i++) {
maxLeft[i] = Math.max(maxLeft[i-1],height[i-1]);
}
for (int i = height.length-2; i >= 0; i--) {
maxRight[i] = Math.max(maxRight[i+1],height[i+1]);
}
for (int i = 1; i < height.length-1; i++) {
int min = Math.min(maxLeft[i],maxRight[i]);
if (min > height[i]) {
sum += min - height[i];
}
}
return sum;
}