记录leetcode的一些解法
- 1. Two Sum
- 2. Add Two Numbers
- 3. 无重复的最长子串
- 4.寻找两个有序数组的中位数
- 5.最长回文子串
- 6. Z 字形变换
- 7. 整数反转
- 8. 字符串转换整数 (atoi)
- 9. 回文数
- 10. 正则表达式匹配
- 11. 盛最多水的容器
- 12. 整数转罗马数字
- 13. 罗马数字转整数
- 14. 最长公共前缀
- 15. 三数之和
- 16. 最接近的三数之和
- 17. 电话号码的字母组合
- 18. 4数之和
- 19. 删除链表的倒数第N个节点
- 20. 有效的括号
- 21. 合并两个有序链表
- 22. 括号生成
- 23. 合并K个排序链表
- 24. 两两交换链表中的节点
- 25. K 个一组翻转链表
- 26. 删除排序数组中的重复项
- 27. 移除元素
- 28. 实现 strStr()
- 30. 串联所有单词的子串
- 31. 下一个排列
- 32.最长有效括号
- 33. 搜索旋转排序数组
- 34.在排序数组中查找元素的第一个和最后一个位置
- 35. 搜索插入位置
- 36. 有效的数独
- 37. 解数独
- 38. 报数
- 39. 组合总和
- 40. 组合总和 II
- 41. 缺失的第一个正数
- 42. 接雨水
- 43. 字符串相乘
- 45. 跳跃游戏 II
- 46. 全排列
- 47. 全排列 II
- 49. 字母异位词分组
- 51&52 N皇后
- 53. 最大子序和
- 54. 螺旋矩阵
- 56.合并区间
- 57.插入区间
- 58. 最后一个单词的长度
- 59. 螺旋矩阵 II
- 60. 第k个排列
- 61.旋转列表
- 62. 不同路径
- 63. 不同路径 II
- 64. 最小路径和
- 66. 加一
- 67. 二进制求和
- 69.x的平方根
- 70. 爬楼梯
- 72. 编辑距离
- 73. 矩阵置零
- 74. 搜索二维矩阵
- 75. 颜色分类
所有算法都是自己写的,有时间会再回来优化,先AC练手,准备按顺序刷题了,不知道能刷多少,希望能刷个200多题把。先立个flag!
1. Two Sum
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] result = new int[2];
int size = nums.length;
for(int i =0; i<size ;i++){
for(int j = i+1 ;j<size ;j++){
int sum = nums[i]+nums[j];
if(sum == target){
result[0]=i;
result[1]=j;
return result;
}
}
}
return null;
}
}
2. Add Two Numbers
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode head = new ListNode(0);
ListNode p = l1;
ListNode q = l2;
ListNode now = head;
while(!(p ==null && q == null)){
if(p != null){
now.val += p.val;
p = p.next;
}
if(q != null){
now.val += q.val;
q = q.next;
}
ListNode next = new ListNode(0);
if(now.val >= 10){
now.val -= 10;
next.val = 1;
}
now.next=next;
if(p==null && q==null && next.val == 0){
now.next = null;
}else{
now = now.next;
}
}
return head;
}
}
3. 无重复的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
class Solution {
public int lengthOfLongestSubstring(String s) {
int length = s.length();
if(length ==0){
return 0;
}
int begin = 0;
int end = 1;
boolean flag = true;
while(end <= length){
flag = true;
for(int i = begin ;i < end; i++){
for(int j = i + 1; j <= end ;j++){
if(j == length ){
begin++;
end++;
flag = false;
break;
}
if(s.charAt(i) == s.charAt(j)){
begin++;
end++;
flag = false;
break;
}
}
if(flag == false){
break;
}
}
if(flag == true){
end = end + 1;
}
}
return end-begin;
}
}
4.寻找两个有序数组的中位数
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
示例 1:
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int size1 = nums1.length;
int size2 = nums2.length;
if(size1 == 0 || size2 == 0){
int[] newnum = size1 > size2 ? nums1 : nums2;
int size = newnum.length;
if(size % 2 == 0){
return 1.0 * ( newnum[size/2] + newnum[size/2 -1] ) / 2;
}else{
return 1.0 * ( newnum[size/2] );
}
}
int totalLength = size1 + size2;
int harfsize = totalLength / 2;
int position1 = 0;
int position2 = 0;
boolean single = true;
if(totalLength % 2 == 0){
single = false;
}
if(single){
while(harfsize > 0){
if(nums1[position1] >= nums2[position2] && position2 < size2-1){
position2++;
}else if(nums1[position1] <= nums2[position2] && position1 < size1-1){
position1++;
}else{
if(position1 < size1-1){
return 1.0 * nums1[position1 + harfsize -1];
}else if(position2 < size2-1){
return 1.0 * nums2[position2 + harfsize -1];
}
}
harfsize--;
}
int finalresult = nums1[position1] < nums2[position2] ? nums1[position1]:nums2[position2];
return 1.0 * finalresult;
}else{
while(harfsize-1 > 0){
if(nums1[position1] >= nums2[position2] && position2 < size2-1){
position2++;
}else if(nums1[position1] <= nums2[position2] && position1 < size1-1){
position1++;
}else{
if(position1 < size1-1){
return 1.0 * (nums1[position1 + harfsize -1] + nums1[position1 + harfsize -2]) / 2 ;
}else if(position2 < size2-1){
return 1.0 * (nums2[position2 + harfsize -1] + nums2[position2 + harfsize -2]) / 2;
}
}
harfsize--;
}
int smallone = nums1[position1] < nums2[position2] ? 1 : 2;
int smallnum = nums1[position1] < nums2[position2] ? nums1[position1] : nums2[position2];
int bignum = 0;
if(position1 < size1-1 && smallone == 1){
bignum = nums1[position1 + 1] < nums2[position2] ? nums1[position1 + 1] : nums2[position2];
}else if(position2 < size2-1 && smallone == 2){
bignum = nums1[position1] < nums2[position2 + 1] ? nums1[position1] : nums2[position2 + 1];
}else{
return 1.0 * (nums1[position1] + nums2[position2]) / 2 ;
}
return 1.0 * (smallnum + bignum) / 2 ;
}
}
}
5.最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”
class Solution {
public String longestPalindrome(String s) {
String max = "";
int maxLength = 0;
int size = s.length();
for(int nowPos = 0 ; nowPos < size ; nowPos++){
int finalPos = nowPos,beforePos = nowPos;
while( finalPos + 1 < size){
if(s.charAt(nowPos) == s.charAt(finalPos+1)){
finalPos ++ ;
}else{
break;
}
}
while( finalPos + 1 < size && beforePos -1 >= 0 ){
if(s.charAt(beforePos -1) == s.charAt(finalPos+1)){
finalPos ++ ;
beforePos --;
}else{
break;
}
}
String nowStr = s.substring(beforePos,finalPos+1);
int nowNum = nowStr.length();
if(nowNum > maxLength){
maxLength = nowNum;
max = new String(nowStr);
}
}
return max;
}
}
6. Z 字形变换
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:
输入: s = “LEETCODEISHIRING”, numRows = 3
输出: “LCIRETOESIIGEDHN”
示例 2:
输入: s = “LEETCODEISHIRING”, numRows = 4
输出: “LDREOEIIECIHNTSG”
解释:
L D R
E O E I I
E C I H N
T S G
class Solution {
public String convert(String s, int numRows) {
StringBuilder str = new StringBuilder();
//长度
int size = s.length();
if(numRows == 1){
return s;
}
for(int row = 0; row < numRows; row++){
if(row < size){
str.append(s.charAt(row));
}else{
break;
}
int add = 2 * (numRows-1-row);
int position = row;
while((position + add) < size){
position = position + add;
if(add != 0){
str.append(s.charAt(position));
}
add = (numRows-1)*2 - add;
}
}
return str.toString();
}
}
7. 整数反转
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
示例 1:
输入: 123
输出: 321
示例 2:
输入: -123
输出: -321
示例 3:
输入: 120
输出: 21
注意:
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。
class Solution {
public int reverse(int x) {
if(x == 0){
return 0;
}
String s=String.valueOf(x);
int i = 0;
StringBuilder str = new StringBuilder();
if(s.charAt(i) == '-'){
i++;
str.append('-');
}
boolean flag = true;
for(int j = s.length()-1 ; j >= i ; j--){
if(flag == true){
if(s.charAt(j) != '0'){
str.append(s.charAt(j));
flag = false;
}
}else{
str.append(s.charAt(j));
}
}
Long num = Long.parseLong(str.toString());
Long l1 = Long.parseLong("2147483647");
Long l2 = Long.parseLong("-2147483647");
if(num.longValue() < l1.longValue() && num.longValue() > l2.longValue()){
return Integer.parseInt(str.toString());
}
return 0;
}
}
8. 字符串转换整数 (atoi)
请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
说明:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
示例 1:
输入: “42”
输出: 42
示例 2:
输入: " -42"
输出: -42
解释: 第一个非空白字符为 ‘-’, 它是一个负号。
我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:
输入: “4193 with words”
输出: 4193
解释: 转换截止于数字 ‘3’ ,因为它的下一个字符不为数字。
示例 4:
输入: “words and 987”
输出: 0
解释: 第一个非空字符是 ‘w’, 但它不是数字或正、负号。
因此无法执行有效的转换。
示例 5:
输入: “-91283472332”
输出: -2147483648
解释: 数字 “-91283472332” 超过 32 位有符号整数范围。
因此返回 INT_MIN (−231) 。
class Solution {
public int myAtoi(String str) {
StringBuilder s = new StringBuilder();
boolean flag0 = true;
boolean flag1 = true;
boolean flag2 = true;
for(int i = 0; i < str.length(); i++){
char c = str.charAt(i);
//‘ ’空仅有开头可以省略
if(c == ' ' && s.length() == 0 && flag2 == true && flag0 ==true){
continue;
}
if(c == '0' && (s.length() == 0 || (flag1 == false && s.length() == 1))){
flag0 = false;
continue;
}
if(c == '-' && s.length() == 0 && flag1==true && flag2 == true && flag0 ==true){
s.append(c);
flag1 = false;
continue;
}
if(c == '+' && s.length() == 0 && flag2==true && flag1==true && flag0 ==true){
flag2 = false;
continue;
}
if(Character.isDigit(c)){
s.append(c);
}else{
if(s.length() == 0){
return 0;
}else{
break;
}
}
if(!Character.isDigit(c) && s.length() == 0){
return 0;
}
}
if(s.length() == 0){
return 0;
}
if(s.length() == 1 && flag1 == false){
return 0;
}
if(s.length() >11 ){
if(flag1 == false){
return -2147483648;
}else{
return 2147483647;
}
}
Long num = Long.parseLong(s.toString());
Long l1 = Long.parseLong("2147483647");
Long l2 = Long.parseLong("-2147483647");
if(num.longValue() > l1.longValue()){
return 2147483647;
}else if(num.longValue() < l2.longValue()){
return -2147483648;
}else{
return Integer.parseInt(s.toString());
}
}
}
9. 回文数
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
示例 1:
输入: 121
输出: true
示例 2:
输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:
输入: 10
输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数。
class Solution {
public boolean isPalindrome(int x) {
String str = String.valueOf(x);
boolean flag = true;
int num = str.length();
for(int i = 0, j = num-1; i <= j; i++,j--){
if(str.charAt(i) != str.charAt(j)){
flag = false;
break;
}
}
return flag;
}
}
10. 正则表达式匹配
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
示例 1:
输入:
s = “aa”
p = “a”
输出: false
解释: “a” 无法匹配 “aa” 整个字符串。
示例 2:
输入:
s = “aa”
p = “a*”
输出: true
解释: 因为 ‘*’ 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 ‘a’。因此,字符串 “aa” 可被视为 ‘a’ 重复了一次。
示例 3:
输入:
s = “ab”
p = “."
输出: true
解释: ".” 表示可匹配零个或多个(’*’)任意字符(’.’)。
示例 4:
输入:
s = “aab”
p = “cab”
输出: true
解释: 因为 ‘*’ 表示零个或多个,这里 ‘c’ 为 0 个, ‘a’ 被重复一次。因此可以匹配字符串 “aab”。
示例 5:
输入:
s = “mississippi”
p = “misisp*.”
输出: false
class Solution {
public boolean isMatch(String s, String p) {
boolean flag = false;
int sizei = s.length();
int sizej = p.length();
if(sizei == 0 && sizej == 0){
return true;
}
if( sizei != 0 && sizej == 0){
return false;
}
if(sizei == 0 && sizej != 0 ){
while( sizej % 2 == 0 && p.charAt(sizej - 1) == '*'){
sizej = sizej - 2;
if(sizej == 0){
return true;
}
}
return false;
}
int posi = sizei - 1;
int posj = sizej - 1;
char ci = s.charAt(posi);
char cj = p.charAt(posj);
if(ci == cj || cj == '.'){
String s1 = s.substring(0,posi);
String s2 = p.substring(0,posj);
return isMatch(s1,s2);
}else if(cj == '*'){
//*前无匹配字符返回错误
if(posj==0){
return false;
}
//连续两个** 返回错误
posj = posj - 1;
char before = p.charAt(posj);
if(before == '*'){
return false;
}
char compare = ci;
flag = flag || isMatch(s,p.substring(0,posj));
while( compare == before || before == '.'){
flag = flag || isMatch(s.substring(0,posi),p.substring(0,posj));
posi--;
if(posi >= 0){
compare = s.charAt(posi);
}else{
break;
}
}
}else{
return false;
}
return flag;
}
}
11. 盛最多水的容器
给定 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例:
输入: [1,8,6,2,5,4,8,3,7]
输出: 49
class Solution {
public int maxArea(int[] height) {
int length = height.length;
int max = 0;
int size =0;
for(int i=0;i<length;i++){
for(int j=i+1;j<length;j++){
int small = height[i]<height[j]?height[i]:height[j];
size = small * (j-i);
if(size>max){
max = size;
}
}
}
return max;
}
}
12. 整数转罗马数字
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。
示例 1:
输入: 3
输出: “III”
示例 2:
输入: 4
输出: “IV”
示例 3:
输入: 9
输出: “IX”
示例 4:
输入: 58
输出: “LVIII”
解释: L = 50, V = 5, III = 3.
示例 5:
输入: 1994
输出: “MCMXCIV”
解释: M = 1000, CM = 900, XC = 90, IV = 4.
class Solution {
public String intToRoman(int num) {
StringBuilder str = new StringBuilder();
int numM = num / 1000;
int restM = num % 1000;
while(numM > 0){
str.append('M');
numM --;
}
if(restM >= 900){
str.append("CM");
restM -= 900;
}
int numD = restM / 500;
int restD = restM % 500;
while(numD > 0){
str.append('D');
numD --;
}
if(restD >= 400){
str.append("CD");
restD -= 400;
}
int numC = restD / 100;
int restC = restD % 100;
while(numC > 0){
str.append('C');
numC --;
}
if(restC >= 90){
str.append("XC");
restC -= 90;
}
int numL = restC / 50;
int restL = restC % 50;
while(numL > 0){
str.append('L');
numL --;
}
if(restL >= 40){
str.append("XL");
restL -= 40;
}
int numX = restL / 10;
int restX = restL % 10;
while(numX > 0){
str.append('X');
numX --;
}
if(restX >= 9){
str.append("IX");
restX -= 9;
}
int numV = restX / 5;
int restV = restX % 5;
while(numV > 0){
str.append('V');
numV --;
}
if(restV >= 4){
str.append("IV");
restV -= 4;
}
while(restV > 0){
str.append('I');
restV --;
}
return str.toString();
}
}
13. 罗马数字转整数
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
示例 1:
输入: “III”
输出: 3
示例 2:
输入: “IV”
输出: 4
示例 3:
输入: “IX”
输出: 9
示例 4:
输入: “LVIII”
输出: 58
解释: L = 50, V= 5, III = 3.
示例 5:
输入: “MCMXCIV”
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.
class Solution {
public int romanToInt(String s) {
int sum = 0;
int pos = 0;
while(pos < s.length()){
StringBuilder a = new StringBuilder();
char b = s.charAt(pos);
a.append(b);
if(pos < s.length() - 1){
char next = s.charAt(pos + 1);
if((b=='C'&&(next == 'M' || next == 'D'))
|| (b == 'X' && (next == 'C' || next == 'L') )
|| (b == 'I' && (next == 'X' || next == 'V') )){
a.append(next);
pos ++;
}
}
String val = a.toString();
switch(val){
case "M": sum += 1000;break;
case "D": sum += 500;break;
case "C": sum += 100;break;
case "L": sum += 50;break;
case "X": sum += 10;break;
case "V": sum += 5;break;
case "I": sum += 1;break;
case "IV": sum += 4;break;
case "IX": sum += 9;break;
case "XC": sum += 90;break;
case "XL": sum += 40;break;
case "CM": sum += 900;break;
case "CD": sum += 400;break;
}
pos ++;
}
return sum;
}
}
14. 最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
示例 1:
输入: [“flower”,“flow”,“flight”]
输出: “fl”
示例 2:
输入: [“dog”,“racecar”,“car”]
输出: “”
解释: 输入不存在公共前缀。
说明:
所有输入只包含小写字母 a-z 。
class Solution {
public String longestCommonPrefix(String[] strs) {
int size = strs.length;
if(size == 0){
return "";
}
StringBuilder s = new StringBuilder();
int sim = 0;
boolean flag = true;
while(flag){
char compare;
if(sim < strs[0].length()){
compare = strs[0].charAt(sim);
}else{
break;
}
for(int i = 1; i < size; i++ ){
if(sim < strs[i].length()){
if(strs[i].charAt(sim) != compare){
flag = false;
break;
}
}else{
flag = false;
break;
}
}
if(flag){
sim++;
s.append(compare);
}
}
return s.toString();
}
}
15. 三数之和
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList();
Map<Integer,Integer> numMap = new HashMap();
TreeSet<Integer> treeSet = new TreeSet<>();
for(int i = 0; i < nums.length; i++){
if(numMap.get(nums[i]) == null){
numMap.put(nums[i],1);
treeSet.add(nums[i]);
}else{
int val = numMap.get(nums[i]);
numMap.put(nums[i], 1 + val);
}
}
Iterator<Integer> it = treeSet.iterator();
while(it.hasNext()) {
Integer intI = it.next();
if(numMap.get(intI) >= 2 ){
if(intI == 0 && numMap.get(intI)< 3 ){
continue;
}else if(numMap.get(-2 * intI) != null){
List<Integer> item = new ArrayList();
item.add(intI);
item.add(intI);
item.add(-2*intI);
result.add(item);
}
}
}
Object[] arr = treeSet.toArray();
for(int i = 0; i < arr.length; i++){
Integer n1 = (Integer)arr[i];
for(int j = i+1; j < arr.length; j++){
Integer n2 = (Integer)arr[j];
if(numMap.get(-n1-n2) != null && -n1-n2 > n2){
List<Integer> item = new ArrayList();
item.add(n1);
item.add(n2);
item.add(-n1-n2);
result.add(item);
}
}
}
return result;
}
}
16. 最接近的三数之和
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
class Solution {
public int threeSumClosest(int[] nums, int target) {
int result = 0;
if(nums.length < 3){
return 0;
}
Arrays.sort(nums);
int min = Integer.MAX_VALUE;
for(int i = 0; i < nums.length; i++){
int before = i + 1;
int end = nums.length - 1;
while(before < end){
int totalNum = nums[i] + nums[before] + nums[end];
int distance = totalNum > target ? totalNum - target : target - totalNum;
if(distance == 0){
return target;
}
if(min > distance){
min = distance;
result = totalNum;
}
if(totalNum > target ){
end--;
}else{
before ++;
}
}
}
return result;
}
}
17. 电话号码的字母组合
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:
输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。
class Solution {
public List<String> letterCombinations(String digits) {
List<String> result = new ArrayList();
if(digits.length() == 0){
return result;
}
String a = digits.substring(0,1);
List<String> result2 = new ArrayList();
switch(a){
case"2":
result2.add("a");
result2.add("b");
result2.add("c");
break;
case"3":
result2.add("d");
result2.add("e");
result2.add("f");
break;
case"4":
result2.add("g");
result2.add("h");
result2.add("i");
break;
case"5":
result2.add("j");
result2.add("k");
result2.add("l");
break;
case"6":
result2.add("m");
result2.add("n");
result2.add("o");
break;
case"7":
result2.add("p");
result2.add("q");
result2.add("r");
result2.add("s");
break;
case"8":
result2.add("t");
result2.add("u");
result2.add("v");
break;
case"9":
result2.add("w");
result2.add("x");
result2.add("y");
result2.add("z");
break;
}
if(digits.length() == 1){
return result2;
}
List<String> suffix = letterCombinations(digits.substring(1,digits.length()));
for(int i = 0; i < result2.size(); i++){
for(int j = 0; j < suffix.size() ; j++){
result.add(result2.get(i) + suffix.get(j));
}
}
return result;
}
}
18. 4数之和
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList();
if(nums.length < 4){
return result;
}
Arrays.sort(nums);
for(int i = 0; i < nums.length; i++){
while(i >= 1 && i < nums.length && nums[i] == nums[i-1]){
i ++;
}
for(int j = i + 1; j < nums.length - 2; j++ ){
while(j >= i + 2 && j < nums.length - 2 && nums[j] == nums[j-1]){
j ++;
}
if(nums[i] + nums[j] > target && target > 0){
break;
}
int beforePos = j + 1;
int endPos = nums.length - 1;
while(beforePos < endPos){
if(nums[i] + nums[j] + nums[beforePos] + nums[endPos] == target){
List<Integer> item = new ArrayList();
item.add(nums[i]);
item.add(nums[j]);
item.add(nums[beforePos]);
item.add(nums[endPos]);
result.add(item);
beforePos++;
endPos--;
while(beforePos < endPos && nums[beforePos] == nums[beforePos - 1]){
beforePos++;
}
while(beforePos < endPos && nums[endPos] == nums[endPos + 1]){
endPos--;
}
}else if(nums[i] + nums[j] + nums[beforePos] + nums[endPos] < target){
beforePos++;
}else{
endPos--;
}
}
}
}
return result;
}
}
19. 删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
Map<Integer,ListNode> map = new HashMap();
int num = 1;
if(head != null){
map.put(num,head);
}else{
return null;
}
ListNode l = head;
while(l.next != null){
ListNode next = l.next;
num++;
map.put(num,next);
l = l.next;
}
int pos = num - n;
if(pos == 0){
return num >= 2 ? map.get(2) : null;
}
ListNode node = map.get(pos);
node.next = node.next.next;
return head;
}
}
20. 有效的括号
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: “()”
输出: true
示例 2:
输入: “()[]{}”
输出: true
示例 3:
输入: “(]”
输出: false
示例 4:
输入: “([)]”
输出: false
示例 5:
输入: “{[]}”
输出: true
class Solution {
public boolean isValid(String s) {
Stack <Character> stack = new Stack();
for(int i = 0; i < s.length(); i++ ){
char a = s.charAt(i);
switch(a){
case'(':
stack.push('(');
break;
case'[':
stack.push('[');
break;
case'{':
stack.push('{');
break;
case')':
if(stack.empty()){
return false;
}
char value = stack.pop();
if(value != '('){
return false;
}
break;
case']':
if(stack.empty()){
return false;
}
char value1 = stack.pop();
if(value1 != '['){
return false;
}
break;
case'}':
if(stack.empty()){
return false;
}
char value2 = stack.pop();
if(value2 != '{'){
return false;
}
break;
}
}
if(!stack.empty()){
return false;
}
return true;
}
}
21. 合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode head;
ListNode pos;
if(l1 != null && l2 != null){
if(l1.val <= l2.val){
head = l1;
l1 = l1.next;
}else{
head = l2;
l2 = l2.next;
}
pos = head;
}else if(l1 == null && l2 != null){
return l2;
}else {
return l1;
}
while(l1 != null && l2 != null){
if(l1.val <= l2.val){
pos.next = l1;
l1 = l1.next;
pos = pos.next;
}else{
pos.next = l2;
l2 = l2.next;
pos = pos.next;
}
}
if(l1 == null && l2 != null){
pos.next = l2;
}else {
pos.next = l1;
}
return head;
}
}
22. 括号生成
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
class Solution {
public List<String> generateParenthesis(int n) {
List<String> result = new ArrayList();
if(n == 0){
return result;
}
if(n == 1){
result.add("()");
return result;
}else{
int nextSize = n-1;
List<String> subString = generateParenthesis(nextSize);
for(int i = 0; i< subString.size(); i++){
result.addAll(findStr(subString.get(i),nextSize));
}
}
return result;
}
private List<String> findStr(String s,int number){
int size = number;
List<Integer> position = new ArrayList();
for(int j = 0; j < 2 * number; j++){
if(s.charAt(j) == '('){
size--;
}
if(size == 0 && s.charAt(j) == ')'){
position.add(j);
}
}
List<String> result = new ArrayList();
for(int i = 0; i < position.size(); i++){
StringBuilder str = new StringBuilder();
str.append(s.substring(0,position.get(i)));
str.append("())");
if(position.get(i) + 1 < number*2){
str.append(s.substring(position.get(i) + 1,number*2));
}
result.add(str.toString());
}
result.add(new String(s+"()"));
return result;
}
}
23. 合并K个排序链表
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0){
return null;
}
if(lists.length == 1){
return lists[0];
}
int position = 1;
ListNode l1 = lists[0];
ListNode head;
ListNode pos;
while(position < lists.length){
ListNode l2 = lists[position];
if(l1 != null && l2 != null){
if(l1.val <= l2.val){
head = l1;
l1 = l1.next;
}else{
head = l2;
l2 = l2.next;
}
pos = head;
}else if(l1 == null && l2 != null){
l1 = l2;
position++;
continue;
}else {
position++;
continue;
}
while(l1 != null && l2 != null){
if(l1.val <= l2.val){
pos.next = l1;
l1 = l1.next;
pos = pos.next;
}else{
pos.next = l2;
l2 = l2.next;
pos = pos.next;
}
}
if(l1 == null && l2 != null){
pos.next = l2;
}else {
pos.next = l1;
}
l1 = head;
position++;
}
return l1;
}
}
24. 两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null){
return null;
}
ListNode positionFirst = head;
ListNode positionSecond = head;
boolean first = true;
while(positionFirst != null){
if(positionFirst.next == null){
break;
}
if(!first){
positionSecond.next = positionFirst.next;
}
positionSecond = positionFirst.next;
positionFirst.next = positionSecond.next;
positionSecond.next = positionFirst;
if(first){
head = positionSecond;
first = false;
}
positionFirst = positionFirst.next;
positionSecond = positionSecond.next;
}
return head;
}
}
25. K 个一组翻转链表
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例 :
给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明 :
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if(k == 0 || k == 1){
return head;
}
Stack<ListNode> stack = new Stack();
ListNode p = head;
ListNode connector = new ListNode(0);
connector.next = head;
ListNode begin = connector;
int number;
while(p != null){
number = k;
while(number > 0 && p != null){
stack.push(p);
number--;
p = p.next;
}
if(number == 0){
while(!stack.isEmpty()){
connector.next = stack.pop();
connector = connector.next;
}
connector.next = p;
}
}
return begin.next;
}
}
26. 删除排序数组中的重复项
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
示例 1:
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}
class Solution {
public int removeDuplicates(int[] nums) {
if(nums.length == 0){
return 0;
}
int beforeVal = nums[0];
int position = 1;
for(int i = 1; i < nums.length; i++){
if(beforeVal != nums[i]){
nums[position] = nums[i];
position++;
beforeVal = nums[i];
}
}
return position;
}
}
27. 移除元素
给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1:
给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,1,2,2,3,0,4,2], val = 2,
函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
注意这五个元素可为任意顺序。
你不需要考虑数组中超出新长度后面的元素。
class Solution {
public int removeElement(int[] nums, int val) {
int size = nums.length;
int before = 0;
int end = nums.length - 1;
while (before <= end){
if(before == end && nums[before] == val){
return before;
}
while(before < nums.length && nums[before] != val){
before ++;
}
while( end >= 0 && nums[end] == val){
size--;
end --;
}
if(before < end){
size--;
nums[before] = nums[end];
nums[end] = val;
before ++;
end--;
}
}
return size;
}
}
28. 实现 strStr()
实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
示例 1:
输入: haystack = “hello”, needle = “ll”
输出: 2
示例 2:
输入: haystack = “aaaaa”, needle = “bba”
输出: -1
说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。
class Solution {
public int strStr(String haystack, String needle) {
if(needle.length() == 0){
return 0;
}
int result = -1;
int compareLength = needle.length();
char compare = needle.charAt(0);
for(int i = 0; i < haystack.length(); i++){
if(haystack.charAt(i) == compare){
if(i+compareLength > haystack.length()){
break;
}
String sub = haystack.substring(i,i+compareLength);
if(sub.equals(needle)){
result = i;
break;
}
}
}
return result;
}
}
30. 串联所有单词的子串
给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。
示例 1:
输入:
s = “barfoothefoobarman”,
words = [“foo”,“bar”]
输出:[0,9]
解释:
从索引 0 和 9 开始的子串分别是 “barfoor” 和 “foobar” 。
输出的顺序不重要, [9,0] 也是有效答案。
示例 2:
输入:
s = “wordgoodgoodgoodbestword”,
words = [“word”,“good”,“best”,“word”]
输出:[]
class Solution {
public List<Integer> findSubstring(String s, String[] words) {
List<Integer> range = new ArrayList();
if(words.length == 0){
return range;
}
int size = words[0].length();
//realMap
Map<String,Integer> wordsMap = new HashMap();
for(int i = 0; i < words.length; i++){
if(wordsMap.get(words[i]) == null){
wordsMap.put(words[i],1);
}else{
wordsMap.put(words[i],1 + wordsMap.get(words[i]));
}
}
int last = size;
int begin = 0;
int last2;
int begin2;
int times = words.length;
while(last <= s.length()){
Map<String,Integer> newMap = new HashMap();
last2 = last;
begin2 = begin;
String sub = s.substring(begin2,last2);
while(wordsMap.get(sub) != null && last2 <= s.length() && times > 0){
sub = s.substring(begin2,last2);
if(newMap.get(sub) == null){
newMap.put(sub,1);
}else{
newMap.put(sub,1 + newMap.get(sub));
}
begin2 += size;
last2 += size;
times -= 1;
if(last2 > s.length()){
break;
}
}
if(wordsMap.size() == newMap.size()){
boolean flag = true;
for(Map.Entry<String,Integer> entry:newMap.entrySet()){
if(entry.getValue() != wordsMap.get(entry.getKey())){
flag = false;
break;
}
}
if(flag){
range.add(begin);
}
}
times = words.length;
begin += 1;
last += 1;
}
return range;
}
}
31. 下一个排列
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
class Solution {
public void nextPermutation(int[] nums) {
int size = nums.length;
if(size == 0){
return ;
}
int max = nums[size - 1];
int exchange = size - 1;
//记录发现第一个递减值的位置
int position = -1;
int now = -1;
for(int i = size-1; i >= 0; i--){
if(max <= nums[i]){
max = nums[i];
exchange = i;
}else{
position = i;
now = nums[i];
break;
}
}
for(int i = position + 1; i < size && position != -1; i++){
if(nums[i] <= max && nums[i] > now){
max = nums[i];
exchange = i;
}
}
if(exchange != -1 && position != -1){
nums[position] = max;
nums[exchange] = now;
}
for(int i = position + 1,j = size -1;i<j;i++,j--){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
32.最长有效括号
给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: “(()”
输出: 2
解释: 最长有效括号子串为 “()”
示例 2:
输入: “)()())”
输出: 4
解释: 最长有效括号子串为 “()()”
class Solution {
public int longestValidParentheses(String s) {
Stack<Character> stack = new Stack();
Stack<Character> temp = new Stack();
int max = 0;
for(int i = 0; i < s.length(); i++){
char now = s.charAt(i);
if(now == '('){
stack.push('(');
}else{
boolean flag = false;
while(!stack.isEmpty()){
char before = stack.pop();
if(before == '('){
stack.push('*');
flag = true;
break;
}else if(before == '*'){
temp.push(before);
continue;
}else{
stack.push(')');
break;
}
}
while(!temp.isEmpty()){
stack.push(temp.pop());
}
if(!flag){
stack.push(')');
}
}
}
int count = 0;
while(!stack.isEmpty()){
char a = stack.pop();
if(a=='*'){
count += 2;
}else{
max = max > count ? max : count;
count = 0;
}
}
max = max > count ? max : count;
return max;
}
}
33. 搜索旋转排序数组
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例 1:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1
class Solution {
public int search(int[] nums, int target) {
int result = -1;
int before = 0;
int end = nums.length -1 ;
int harf;
while(before <= end){
harf = (end - before) / 2 + before;
if(before == harf && nums[before] != target && nums[end] != target){
break;
}
if(nums[before] == target){
result = before;
break;
}
if(nums[end] == target){
result = end;
break;
}
if(nums[before] > target && nums[end] < target){
break;
}
if(nums[before] > target && nums[end] > target){
if(nums[harf] > nums[end]){
before = harf;
}else if(nums[harf] > target){
end = harf;
}else{
before = harf;
}
continue;
}
if(nums[before] < target && nums[end] < target){
if(nums[harf] < nums[before]){
end = harf;
}else if(nums[harf] > target){
end = harf;
}else{
before = harf;
}
continue;
}
if(target >= nums[harf]){
before = harf;
}else{
end = harf;
}
}
return result;
}
}
34.在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] result = new int[2];
result[0] = -1;
result[1] = -1;
int before = 0;
int end = nums.length - 1;
if(end < before || target < nums[before] || target > nums[end]){
return result;
}
int harf;
boolean flag = false;
while(before <= end){
if( end-before <= 1 && nums[before] != target && nums[end] != target){
break;
}
if( end-before <= 1 && (nums[before] != target && nums[end] == target)){
result[0] = end;
result[1] = end;
break;
}
harf = (end -before) / 2 + before;
if(nums[harf] < target){
before = harf;
}else if(nums[harf] > target){
end = harf;
}else{
flag = true;
break;
}
}
if(!flag){
return result;
}
result[0]=findPos(nums,before,end,target,1);
result[1]=findPos(nums,before,end,target,2);
return result;
}
public int findPos(int[] nums, int before,int end,int target ,int type){
int mid = (end - before)/2 + before;
while(before < end){
if(nums[mid] > target || (target == nums[mid] && type == 1)){
end = mid;
}else{
before = mid+1;
}
mid = (end - before)/2 + before;
}
if(type == 2 && nums[before]!=target){
return before-1;
}
return before;
}
}
35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 1:
输入: [1,3,5,6], 5
输出: 2
示例 2:
输入: [1,3,5,6], 2
输出: 1
示例 3:
输入: [1,3,5,6], 7
输出: 4
示例 4:
输入: [1,3,5,6], 0
输出: 0
class Solution {
public int searchInsert(int[] nums, int target) {
int before = 0;
int end = nums.length - 1;
if(nums[before] > target || nums.length == 0){
return 0;
}
if(nums[end]<target){
return nums.length;
}
int mid = (end - before) /2 + before;
while(end >= before){
if(end == before){
break;
}
if(nums[mid] > target){
end = mid;
}else if(nums[mid] < target){
before = mid + 1;
}else if(nums[mid]==target){
break;
}
mid = (end - before) /2 + before;
}
return mid;
}
}
36. 有效的数独
判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
上图是一个部分填充的有效的数独。
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
示例 1:
输入:
[
[“5”,“3”,".",".",“7”,".",".",".","."],
[“6”,".",".",“1”,“9”,“5”,".",".","."],
[".",“9”,“8”,".",".",".",".",“6”,"."],
[“8”,".",".",".",“6”,".",".",".",“3”],
[“4”,".",".",“8”,".",“3”,".",".",“1”],
[“7”,".",".",".",“2”,".",".",".",“6”],
[".",“6”,".",".",".",".",“2”,“8”,"."],
[".",".",".",“4”,“1”,“9”,".",".",“5”],
[".",".",".",".",“8”,".",".",“7”,“9”]
]
输出: true
示例 2:
输入:
[
[“8”,“3”,".",".",“7”,".",".",".","."],
[“6”,".",".",“1”,“9”,“5”,".",".","."],
[".",“9”,“8”,".",".",".",".",“6”,"."],
[“8”,".",".",".",“6”,".",".",".",“3”],
[“4”,".",".",“8”,".",“3”,".",".",“1”],
[“7”,".",".",".",“2”,".",".",".",“6”],
[".",“6”,".",".",".",".",“2”,“8”,"."],
[".",".",".",“4”,“1”,“9”,".",".",“5”],
[".",".",".",".",“8”,".",".",“7”,“9”]
]
输出: false
解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。
但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。
说明:
一个有效的数独(部分已被填充)不一定是可解的。
只需要根据以上规则,验证已经填入的数字是否有效即可。
给定数独序列只包含数字 1-9 和字符 ‘.’ 。
给定数独永远是 9x9 形式的。
class Solution {
public boolean isValidSudoku(char[][] board) {
for(int i = 0; i < 9; i++){
Set<Character> set = new HashSet();
Set<Character> set2 = new HashSet();
for(int j = 0; j < 9; j++){
if(board[i][j] != '.'){
if(set.contains(board[i][j])){
return false;
}
set.add(board[i][j]);
}
if(board[j][i] != '.'){
if(set2.contains(board[j][i])){
return false;
}
set2.add(board[j][i]);
}
}
}
for(int i = 0; i < 9; i = i+3){
for(int m = 0; m < 9; m=m+3){
Set<Character> set = new HashSet();
for(int j = i; j < i+3; j++){
for(int k = m; k < m+3; k++){
if(board[k][j] != '.'){
if(set.contains(board[k][j])){
return false;
}
set.add(board[k][j]);
}
}
}
}
}
return true;
}
}
37. 解数独
编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 ‘.’ 表示。
一个数独。
答案被标成红色。
Note:
给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。
class Solution {
public void solveSudoku(char[][] board) {
System.out.println(search(board,0,0));
}
public boolean search(char[][] board,int x,int y){
for(int i = x; i < 9;i++){
int j = 0;
if(i == x){
j = y;
}
for(; j < 9; j++){
if(board[i][j] == '.'){
Set set = findOnly(board,i,j);
if(set.size() == 0){
return false;
}
Iterator iterator = set.iterator();
while(iterator.hasNext()){
int a = (Integer)iterator.next();
board[i][j] = (char) a;
if(search(board,i,j+1)){
return true;
}else{
board[i][j] = '.';
}
}
if(board[i][j] == '.'){
return false;
}
}
}
}
return true;
}
public Set findOnly(char[][] board,int x,int y){
Set set = new HashSet();
for(int i = 49; i <= 57; i++){
set.add(i);
}
int squrex = (x/3) * 3;
int squrey = (y/3) * 3;
//遍历行
for(int i = 0; i < 9; i++){
if(board[x][i] != '.'){
set.remove((int)board[x][i]);
}
if(board[i][y] != '.'){
set.remove((int)board[i][y]);
}
}
for(int i = squrex;i<squrex+3;i++){
for(int j =squrey;j<squrey+3;j++){
if(board[i][j] != '.'){
set.remove((int)board[i][j]);
}
}
}
return set;
}
}
38. 报数
报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:
-
1
-
11
-
21
-
1211
-
111221
1 被读作 “one 1” (“一个一”) , 即 11。
11 被读作 “two 1s” (“两个一”), 即 21。
21 被读作 “one 2”, “one 1” (“一个二” , “一个一”) , 即 1211。
给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。
注意:整数顺序将表示为一个字符串。
示例 1:
输入: 1
输出: “1”
示例 2:
输入: 4
输出: “1211”
class Solution {
public String countAndSay(int n) {
String before = "1";
int count = 1;
char cb = '1';
while(n > 1){
StringBuilder str = new StringBuilder();
cb = before.charAt(0);
for(int i = 1; i < before.length(); i++){
if(cb == before.charAt(i)){
count ++;
}else{
str.append(count);
str.append(cb);
cb = before.charAt(i);
count = 1;
}
}
str.append(count);
str.append(cb);
count = 1;
n--;
before = str.toString();
}
return before;
}
}
39. 组合总和
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:
输入: candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> results = new ArrayList();
Arrays.sort(candidates);
return find(candidates, target,0);
}
public List<List<Integer>> find(int[] candidates, int target,int now) {
List<List<Integer>> results = new ArrayList();
for(int i = now; i < candidates.length; i++){
if(candidates[i] < target){
List<List<Integer>> lists = find(candidates,target-candidates[i],i);
for(int j = 0;j<lists.size();j++){
List newlist = lists.get(j);
newlist.add(0,candidates[i]);
results.add(newlist);
}
}else if(candidates[i]==target){
List list = new ArrayList();
list.add(0,candidates[i]);
results.add(list);
}else{
break;
}
}
return results;
}
}
40. 组合总和 II
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> results = new ArrayList();
if(candidates.length == 0){
return results;
}
Arrays.sort(candidates);
return find(candidates,target,0,-1);
}
public List<List<Integer>> find(int[] candidates, int target,int nowPos,int nowVal) {
List<List<Integer>> results = new ArrayList();
int compare = 0;
for(int i = nowPos; i < candidates.length; i++){
if(i == nowPos){
compare = candidates[nowPos];
}else if(candidates[i] == compare || (i > nowPos && candidates[i] ==nowVal)){
continue;
}else{
compare = candidates[i];
}
if(candidates[i] < target){
List<List<Integer>> lists = find(candidates,target-candidates[i],i+1,candidates[i]);
for(int j = 0;j<lists.size();j++){
List newlist = lists.get(j);
newlist.add(0,candidates[i]);
results.add(newlist);
}
}else if(candidates[i]==target){
List list = new ArrayList();
list.add(0,candidates[i]);
results.add(list);
}else{
break;
}
}
return results;
}
}
41. 缺失的第一个正数
给定一个未排序的整数数组,找出其中没有出现的最小的正整数。
示例 1:
输入: [1,2,0]
输出: 3
示例 2:
输入: [3,4,-1,1]
输出: 2
示例 3:
输入: [7,8,9,11,12]
输出: 1
class Solution {
public int firstMissingPositive(int[] nums) {
Map<Integer,Integer> map = new HashMap();
for(int i = 0; i < nums.length; i++){
map.put(nums[i],nums[i]);
}
boolean flag = false;
int a = 1;
while(!flag){
if(map.get(a) == null){
flag = true;
}else{
a++;
}
}
return a;
}
}
42. 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。
示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
class Solution {
public int trap(int[] height) {
int result = 0;
boolean findBefore = false;
int beforePos = 0;
int beforeVal = 0;
int lower = 0;
for(int i = 0; i < height.length; i++){
if(!findBefore && height[i] == 0){
continue;
}
if(!findBefore && height[i] != 0){
beforePos = i;
beforeVal = height[i];
findBefore = true;
lower = height[i];
continue;
}
lower = height[i] < lower? height[i] : lower;
if(height[i] > lower && lower < beforeVal){
int compare = beforeVal < height[i] ? beforeVal : height[i];
result += cal(beforePos,i,height,compare);
lower = compare;
if(beforeVal <= height[i]){
beforePos = i;
beforeVal = height[i];
lower = height[i];
}
}else if(height[i] > lower && lower == beforeVal){
beforePos = i;
beforeVal = height[i];
lower = height[i];
}
}
return result;
}
public int cal(int beforePos,int endPos,int[] height ,int compare){
int sum = 0;
for(int i = beforePos + 1; i < endPos; i++){
if(height[i] >= compare){
continue;
}
sum += compare-height[i];
height[i] = compare;
}
return sum;
}
}
43. 字符串相乘
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
示例 1:
输入: num1 = “2”, num2 = “3”
输出: “6”
示例 2:
输入: num1 = “123”, num2 = “456”
输出: “56088”
说明:
num1 和 num2 的长度小于110。
num1 和 num2 只包含数字 0-9。
num1 和 num2 均不以零开头,除非是数字 0 本身。
不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。
class Solution {
public String multiply(String num1, String num2) {
int maxsize = num1.length() + num2.length();
int[] result = new int[maxsize];
int i = num1.length() - 1;
int j = num2.length() - 1;
int pos = maxsize - 1;
int leave = 0;
int sum = 0;
while (j >= 0) {
while (i >= 0) {
int a = (int) num1.charAt(i) - 48;
sum = ((int) num1.charAt(i) - 48) * ((int) num2.charAt(j) - 48) + leave + result[pos];
leave = sum / 10;
result[pos] =sum % 10;
i--;
pos--;
}
j --;
result[pos] += leave;
leave = 0;
i= num1.length()-1;
pos = pos + num1.length() - 1;
}
boolean first = false;
StringBuilder str = new StringBuilder();
for (int k = 0; k < maxsize; k++) {
if (!first && result[k] == 0) {
continue;
}
if (!first && result[k] != 0) {
first = true;
}
str.append(result[k]);
}
if(str.length() == 0){
str.append(0);
}
return str.toString();
}
}
45. 跳跃游戏 II
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例:
输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
说明:
假设你总是可以到达数组的最后一个位置。
class Solution {
public int jump(int[] nums) {
int size = nums.length;
if(size <= 1){
return 0;
}
int[] jump = new int[size];
for(int i = 0; i < size - 1; i++){
jump[i] = Integer.MAX_VALUE - 1;
}
jump[size - 1] = 0;
for(int i = size -2; i >= 0; i--){
for(int j = i + 1; j <= i + nums[i] && j < size; j++ ){
jump[i] = jump[i] < 1 +jump[j] ? jump[i] : jump[j]+1;
}
}
return jump[0];
}
}
46. 全排列
给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
class Solution {
public List<List<Integer>> permute(int[] nums) {
int[] select = new int[nums.length];
if(nums.length == 0){
List<List<Integer>> results = new ArrayList();
List<Integer> result = new ArrayList();
results.add(result);
return results;
}
return get(nums,select);
}
public List<List<Integer>> get(int[] nums,int[] select) {
List<List<Integer>> results = new ArrayList();
for(int i = 0; i < nums.length ; i++){
if(select[i] == 1){
continue;
}
select[i] = 1;
List<List<Integer>> lists = get(nums,select);
if(lists.size() == 0){
List<Integer> list = new ArrayList();
lists.add(list);
}
for(int j = 0; j < lists.size(); j++){
lists.get(j).add(nums[i]);
}
results.addAll(lists);
select[i] = 0;
}
return results;
}
}
47. 全排列 II
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
Arrays.sort(nums);
int[] select = new int[nums.length];
return get(nums,select);
}
public List<List<Integer>> get(int[] nums,int[] select) {
List<List<Integer>> results = new ArrayList();
for(int i = 0; i < nums.length ; i++){
if(select[i] == 1 || (i > 0 && nums[i] == nums[i - 1] && select[i-1] == 0)){
continue;
}
select[i] = 1;
List<List<Integer>> lists = get(nums,select);
if(lists.size() == 0){
List<Integer> list = new ArrayList();
lists.add(list);
}
for(int j = 0; j < lists.size(); j++){
lists.get(j).add(nums[i]);
}
results.addAll(lists);
select[i] = 0;
}
return results;
}
}
49. 字母异位词分组
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
示例:
输入: [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”],
输出:
[
[“ate”,“eat”,“tea”],
[“nat”,“tan”],
[“bat”]
]
说明:
所有输入均为小写字母。
不考虑答案输出的顺序。
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
List<List<String>> result = new ArrayList();
Map<List<Integer>,List<String>> temp = new HashMap();
for(int i = 0; i < strs.length; i++){
String s = strs[i];
ArrayList<Integer> list = new ArrayList();
for(int j = 0 ; j < s.length(); j++){
int a =s.charAt(j);
list.add(a);
}
Collections.sort(list);
List<String> strings = temp.get(list);
if(strings == null){
strings = new ArrayList();
}
strings.add(s);
temp.put(list,strings);
}
for(List<String> s : temp.values()){
result.add(s);
}
return result;
}
}
51&52 N皇后
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
示例:
输入: 4
输出: [
[".Q…", // 解法 1
“…Q”,
“Q…”,
“…Q.”],
["…Q.", // 解法 2
“Q…”,
“…Q”,
“.Q…”]
]
解释: 4 皇后问题存在两个不同的解法。
class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> resuls = new ArrayList();
List<String> now = new ArrayList<>();
if (n > 0) {
solve(resuls, now, 0, n);
}
return resuls;
}
a
private void solve(List<List<String>> results, List<String> now, int row, int n) {
for (int j = 0; j < n; j++) {
if (check(now, row, j, n)) {a
now.add(getString(j, n));
if (row == n - 1) {
List<String> strings = new ArrayList<>();
strings.addAll(now);
results.add(strings);
now.remove(row);
}
if (row < n - 1) {
solve(results, now, row + 1, n);
now.remove(row);
}
}
}
}
private boolean check(List<String> now, int x, int y, int n) {
for (int i = 0; i < now.size(); i++) {
if (now.get(i).charAt(y) == 'Q' ||
(y + i - x >= 0 && y + i - x < y && now.get(i).charAt(y + i - x) == 'Q') ||
(y - i + x > y && y - i + x < n && now.get(i).charAt(y - i + x) == 'Q')) {
return false;
}
}
return true;
}
private String getString(int j, int n) {
StringBuilder stringBuilder = new StringBuilder();
for (int k = 0; k < n; k++) {
if (k == j) {
stringBuilder.append("Q");
} else {
stringBuilder.append(".");
}
}
return stringBuilder.toString();
}
}
53. 最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
class Solution {
public int maxSubArray(int[] nums) {
int result = nums[0];
int sum = 0;
for (int num : nums) {
if (sum > 0){
sum += num;
}else{
sum = num;
}
result =result>sum?result:sum;
}
return result;
}
}
54. 螺旋矩阵
给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。
示例 1:
输入:
[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
]
输出: [1,2,3,6,9,8,7,4,5]
示例 2:
输入:
[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12]
]
输出: [1,2,3,4,8,12,11,10,9,5,6,7]
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> result = new ArrayList<>();
int rownum = matrix.length;
if (rownum == 0) {
return result;
}
int columnnum = matrix[0].length;
if (columnnum == 0) {
return result;
}
int[][] check = new int[rownum][columnnum];
result.addAll(check(rownum, columnnum, matrix, check, 0, 0, -1));
return result;
}
public List<Integer> check(int rownum, int column, int[][] matrix, int[][] check, int type, int x, int y) {
List<Integer> result = new ArrayList<>();
boolean findnext = false;
type = type % 4;
if (type == 0) {
y++;
while (y < column && check[x][y] == 0) {
findnext = true;
result.add(matrix[x][y]);
check[x][y] = -1;
y++;
}
y--;
} else if (type == 1) {
x++;
while (x < rownum && check[x][y] == 0) {
findnext = true;
result.add(matrix[x][y]);
check[x][y] = -1;
x++;
}
x--;
}else if (type == 2) {
y--;
while (y >= 0 && check[x][y] == 0) {
findnext = true;
result.add(matrix[x][y]);
check[x][y] = -1;
y--;
}
y++;
}else{
x--;
while (x >= 0 && check[x][y] == 0) {
findnext = true;
result.add(matrix[x][y]);
check[x][y] = -1;
x--;
}
x++;
}
if(findnext){
result.addAll(check(rownum, column, matrix, check, ++type, x, y));
}
return result;
}
}
56.合并区间
给出一个区间的集合,请合并所有重叠的区间。
示例 1:
输入: [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入: [[1,4],[4,5]]
输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。
class Solution {
class Node implements Comparable<Node>{
private Integer before;
private Integer end;
public Node(Integer before, Integer end) {
this.before = before;
this.end = end;
}
public Integer getBefore() {
return before;
}
public void setBefore(Integer before) {
this.before = before;
}
public Integer getEnd() {
return end;
}
public void setEnd(Integer end) {
this.end = end;
}
@Override
public int compareTo(Node o) {
if(this.before.compareTo(o.getBefore())!=0){
return this.before.compareTo(o.getBefore());
}
return this.end.compareTo(o.getEnd());
}
}
public int[][] merge(int[][] intervals) {
Set<Node> nodes = new TreeSet<>();
List<Node> nodeList = new ArrayList<>();
for(int i = 0; i< intervals.length;i++){
Node node = new Node(intervals[i][0],intervals[i][1]);
nodes.add(node);
}
Iterator it = nodes.iterator();
Node node;
Node compareNode;
while(it.hasNext()){
node = (Node) it.next();
if(nodeList.size() == 0){
nodeList.add(new Node(node.getBefore(),node.getEnd()));
continue;
}
compareNode = nodeList.get(nodeList.size() - 1);
if(node.getBefore() > compareNode.getEnd()){
nodeList.add(new Node(node.getBefore(),node.getEnd()));
}else if(node.getEnd() > compareNode.getEnd()){
nodeList.add(new Node(compareNode.getBefore(),node.getEnd()));
nodeList.remove(nodeList.size() - 2);
}
}
int size = nodeList.size();
int[][] result = new int[size][2];
for(int i = 0 ; i < size; i++){
result[i][0] = nodeList.get(i).getBefore();
result[i][1] = nodeList.get(i).getEnd();
}
return result;
}
}
57.插入区间
给出一个无重叠的 ,按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
示例 1:
输入: intervals = [[1,3],[6,9]], newInterval = [2,5]
输出: [[1,5],[6,9]]
示例 2:
输入: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
输出: [[1,2],[3,10],[12,16]]
解释: 这是因为新的区间 [4,8] 与 [3,5],[6,7],[8,10] 重叠。
class Solution {
class Node implements Comparable<Node> {
private Integer before;
private Integer end;
public Node(Integer before, Integer end) {
this.before = before;
this.end = end;
}
public Integer getBefore() {
return before;
}
public void setBefore(Integer before) {
this.before = before;
}
public Integer getEnd() {
return end;
}
public void setEnd(Integer end) {
this.end = end;
}
@Override
public int compareTo(Node o) {
if (this.before.compareTo(o.getBefore()) != 0) {
return this.before.compareTo(o.getBefore());
}
return this.end.compareTo(o.getEnd());
}
}
public int[][] insert(int[][] intervals, int[] newInterval) {
Set<Node> nodeList = new TreeSet<>();
if (newInterval.length == 0) return intervals;
int before = newInterval[0];
int end = newInterval[1];
int compareBefore = 0;
int compareEnd = 0;
for (int i = 0; i < intervals.length; i++) {
compareBefore = intervals[i][0];
compareEnd = intervals[i][1];
if (compareEnd < before || compareBefore > end) {
nodeList.add(new Node(compareBefore, compareEnd));
} else if (compareBefore < before && compareEnd <= end) {
before = compareBefore;
} else if (compareBefore < before && compareEnd > end) {
before = compareBefore;
end = compareEnd;
} else if (compareBefore <= end && compareEnd > end) {
end = compareEnd;
}
}
nodeList.add(new Node(before, end));
int size = nodeList.size();
int[][] result = new int[size][2];
Iterator iterator = nodeList.iterator();
int i = 0;
while (iterator.hasNext()) {
Node node = (Node) iterator.next();
result[i][0] = node.getBefore();
result[i][1] = node.getEnd();
i++;
}
return result;
}
}
58. 最后一个单词的长度
给定一个仅包含大小写字母和空格 ’ ’ 的字符串,返回其最后一个单词的长度。
如果不存在最后一个单词,请返回 0 。
说明:一个单词是指由字母组成,但不包含任何空格的字符串。
示例:
输入: “Hello World”
输出: 5
class Solution {
public int lengthOfLastWord(String s) {
if(s.length() == 0 ){
return 0;
}
String[] strings = s.split(" ");
if(strings.length == 0){
return 0;
}
String sss = strings[strings.length-1];
return sss.length();
}
}
59. 螺旋矩阵 II
给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3
输出:
[
[ 1, 2, 3 ],
[ 8, 9, 4 ],
[ 7, 6, 5 ]
]
class Solution {
public int[][] generateMatrix(int n) {
int[][] status = new int[n][n];
int[][] result = new int[n][n];
int pos = 0;
findPosition(result,status,0,-1,n,pos,1);
return result;
}
public int[][] findPosition(int[][] result,int[][] status,int x,int y ,int n,int pos,int number){
if(number>n*n){
return result;
}
switch(pos){
case 0:
y++;
break;
case 1:
x++;
break;
case 2:
y--;
break;
case 3:
x--;
break;
}
if(y<n && y>=0 && x<n && x>=0 && status[x][y]==0){
status[x][y]=1;
result[x][y]=number;
}else{
switch(pos){
case 0:
y--;
break;
case 1:
x--;
break;
case 2:
y++;
break;
case 3:
x++;
break;
}
pos = (pos+1)%4;
return findPosition(result,status,x,y,n,pos,number);
}
number++;
return findPosition(result,status,x,y,n,pos,number);
}
}
60. 第k个排列
给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
“123”
“132”
“213”
“231”
“312”
“321”
给定 n 和 k,返回第 k 个排列。
说明:
给定 n 的范围是 [1, 9]。
给定 k 的范围是[1, n!]。
示例 1:
输入: n = 3, k = 3
输出: “213”
示例 2:
输入: n = 4, k = 9
输出: “2314”
class Solution {
public String getPermutation(int n, int k) {
k = k-1;
int divided = 0;
int mul = 0;
List<Integer> list = new ArrayList<>();
for(int i = 1; i<=n;i++){
list.add(i);
}
StringBuilder stringBuilder = new StringBuilder();
for (int i = n - 1; i >= 1; i--) {
mul = NMul(i);
divided = k / mul;
k = k % mul;
stringBuilder.append(list.get(divided));
list.remove(divided);
}
stringBuilder.append(list.get(0));
return stringBuilder.toString();
}
private int NMul(int n) {
int val = 1;
for (int i = n; i >= 1; i--) {
val *= i;
}
return val;
}
}
61.旋转列表
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode rotateRight(ListNode head, int k) {
if(head == null){
return head;
}
ListNode pHead = head;
int size = 1;
while(pHead.next != null){
size++;
pHead = pHead.next;
}
pHead.next = head;
k = size-(k%size);
for(int i = 0; i < k ; i++){
head = head.next;
}
pHead = head;
while(pHead.next != head){
pHead = pHead.next;
}
pHead.next = null;
return head;
}
}
62. 不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?
例如,上图是一个7 x 3 的网格。有多少可能的路径?
说明:m 和 n 的值均不超过 100。
示例 1:
输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
- 向右 -> 向右 -> 向下
- 向右 -> 向下 -> 向右
- 向下 -> 向右 -> 向右
示例 2:
输入: m = 7, n = 3
输出: 28
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m+1][n+1];
dp[1][1] = 1;
for(int i = 1;i < m+1;i++) {
for(int j = 1;j < n+1;j++) {
if(i == 1 && j == 1) continue;
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
return dp[m][n];
}
}
63. 不同路径 II
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
说明:m 和 n 的值均不超过 100。
示例 1:
输入:
[
[0,0,0],
[0,1,0],
[0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
- 向右 -> 向右 -> 向下 -> 向下
- 向下 -> 向下 -> 向右 -> 向右
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
if(m <= 0){
return 0;
}
int n = obstacleGrid[0].length;
int[][] dp = new int[m+1][n+1];
dp[1][1] = 1;
for(int i = 1;i < m+1;i++) {
for(int j = 1;j < n+1;j++) {
if(obstacleGrid[i-1][j-1]==1){
dp[i][j] = 0;
}else if(i == 1 && j == 1){
continue;
}else{
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
}
return dp[m][n];
}
}
64. 最小路径和
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
class Solution {
public int minPathSum(int[][] grid) {
int m = grid.length;
if(m <= 0){
return 0;
}
int n = grid[0].length;
int[][] dp = new int[m+1][n+1];
for(int i = 0; i < m+1; i++){
dp[i][0] = Integer.MAX_VALUE;
}
for(int i = 0; i < n+1; i++){
dp[0][i] = Integer.MAX_VALUE;
}
for(int i = 1;i < m+1;i++) {
for(int j = 1;j < n+1;j++) {
if(i == 1 && j == 1){
dp[1][1] = grid[0][0];
}else{
dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1])+ grid[i-1][j-1];
}
}
}
return dp[m][n];
}
}
66. 加一
给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
示例 1:
输入: [1,2,3]
输出: [1,2,4]
解释: 输入数组表示数字 123。
示例 2:
输入: [4,3,2,1]
输出: [4,3,2,2]
解释: 输入数组表示数字 4321。
class Solution {
public int[] plusOne(int[] digits) {
int size = digits.length;
int number = 0;
boolean find = false;
while(!find && size >= 1){
number = digits[size -1]+1;
if(number < 10){
find = true;
}
digits[size -1] = number % 10;
size--;
}
if(!find){
int[] newDigits = new int[digits.length+1];
newDigits[0] = 1;
for(int i = 0; i< digits.length;i++){
newDigits[i+1] = digits[i];
}
return newDigits;
}
return digits;
}
}
67. 二进制求和
给定两个二进制字符串,返回他们的和(用二进制表示)。
输入为非空字符串且只包含数字 1 和 0。
示例 1:
输入: a = “11”, b = “1”
输出: “100”
示例 2:
输入: a = “1010”, b = “1011”
输出: “10101”
class Solution {
public String addBinary(String a, String b) {
int aSize = a.length()-1;
int bSize = b.length()-1;
List<Integer> list = new LinkedList<>();
int position = 0;
int value = 0;
int addValue = 0;
while(position <= aSize || position <= bSize){
int ca = position > aSize?0:a.charAt(aSize-position)-'0';
int cb = position > bSize?0:b.charAt(bSize-position)-'0';
value = addValue+ca+cb;
if(value/2 == 1){
addValue = 1;
value = value%2;
}else{
addValue = 0;
}
list.add(0,value);
value = 0;
position++;
}
if(addValue == 1){
list.add(0,1);
}
if(list.size()==0){
return "0";
}
StringBuilder str = new StringBuilder();
for(int i = 0;i<list.size();i++){
str.append(list.get(i));
}
return str.toString();
}
}
69.x的平方根
实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4
输出: 2
示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842…,
由于返回类型是整数,小数部分将被舍去。
class Solution {
public int mySqrt(int x) {
return compare(0,x,x);
}
public int compare(int before, int end, int target){
if(before == end){
return before;
}
if(end - before == 1){
if(end*end == target){
return end;
}
return before;
}
int harf = (end-before)/2 +before;
if(harf == target/harf){
return harf;
}
if(harf > target/harf){
end = harf;
}else{
before = harf;
}
return compare(before,end,target);
}
}
70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
- 1 阶 + 1 阶
- 2 阶
示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
- 1 阶 + 1 阶 + 1 阶
- 1 阶 + 2 阶
- 2 阶 + 1 阶
class Solution {
public int climbStairs(int n) {
if( n == 0 || n == 1){
return 1;
}
int[] result = new int[n+1];
result[0] = 1;
result[1] = 1;
for(int i = 2; i < n+1; i++){
result[i] = result[i-1] + result[i-2];
}
return result[n];
}
}
72. 编辑距离
给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
示例 1:
输入: word1 = “horse”, word2 = “ros”
输出: 3
解释:
horse -> rorse (将 ‘h’ 替换为 ‘r’)
rorse -> rose (删除 ‘r’)
rose -> ros (删除 ‘e’)
示例 2:
输入: word1 = “intention”, word2 = “execution”
输出: 5
解释:
intention -> inention (删除 ‘t’)
inention -> enention (将 ‘i’ 替换为 ‘e’)
enention -> exention (将 ‘n’ 替换为 ‘x’)
exention -> exection (将 ‘n’ 替换为 ‘c’)
exection -> execution (插入 ‘u’)
class Solution {
public int minDistance(String word1, String word2) {
if(word1.length() == 0 || word2.length() == 0){
return Math.abs(word1.length()-word2.length());
}
int[][] result = new int[word1.length()+1][word2.length()+1];
for(int i = 0; i <= word2.length();i++){
result[0][i] = i;
}
for(int i = 0; i <= word1.length();i++){
result[i][0] = i;
}
if(word1.charAt(0) == word2.charAt(0)){
result[1][1] = 0;
}else{
result[1][1] = 1;
}
char s1;
char s2;
int min = 0;
for(int i = 1; i <= word1.length(); i++){
s1 = word1.charAt(i-1);
for(int j = 1; j <= word2.length(); j++){
if(i==1 && j==1) continue;
s2 = word2.charAt(j-1);
if(s1 == s2){
result[i][j] = result[i-1][j-1];
}else{
min = Math.min(result[i-1][j-1],result[i][j-1]);
result[i][j] = 1+Math.min(min,result[i-1][j]);
}
}
}
return result[word1.length()][word2.length()];
}
}
73. 矩阵置零
给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。
示例 1:
输入:
[
[1,1,1],
[1,0,1],
[1,1,1]
]
输出:
[
[1,0,1],
[0,0,0],
[1,0,1]
]
示例 2:
输入:
[
[0,1,2,0],
[3,4,5,2],
[1,3,1,5]
]
输出:
[
[0,0,0,0],
[0,4,5,0],
[0,3,1,0]
]
进阶:
一个直接的解决方案是使用 O(mn) 的额外空间,但这并不是一个好的解决方案。
一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案。
你能想出一个常数空间的解决方案吗?
class Solution {
public void setZeroes(int[][] matrix) {
int row = matrix.length;
if(row == 0){
return;
}
int column = matrix[0].length;
int[] columns = new int[column];
boolean isZero = false;
boolean containsZero = false;
for(int i = 0; i<row;i++){
for(int j = 0 ; j < column; j++){
if(isZero){
matrix[i-1][j] = 0;
}
if(matrix[i][j] == 0){
columns[j] = 1;
containsZero = true;
}
}
if(containsZero){
isZero = true;
}else{
isZero = false;
}
containsZero = false;
}
if(isZero){
for(int j = 0 ; j < column; j++){
matrix[row-1][j] = 0;
}
}
for(int i = 0; i < column; i++){
if(columns[i]==1){
for(int j = 0; j < row; j ++){
matrix[j][i] = 0;
}
}
}
}
}
74. 搜索二维矩阵
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。
示例 1:
输入:
matrix = [
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
target = 3
输出: true
示例 2:
输入:
matrix = [
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
target = 13
输出: false
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int row = matrix.length;
if(row == 0){
return false;
}
int column = matrix[0].length;
if(column == 0){
return false;
}
return search(matrix,target,0,0,row - 1,column - 1);
}
public boolean find(int[][] matrix, int target,int beforeX,int beforeY,int endX, int endY){
if(beforeX >= endX - 1 || beforeY >= endY - 1){
search(matrix,target,beforeX,beforeY,endX,endY);
}
int harfX = ( beforeX + endX ) / 2;
int harfY = ( beforeY + endY) / 2;
if(matrix[harfX][harfY] == target){
return true;
}
if(matrix[harfX][harfY] < target){
return find(matrix,target,harfX,harfY,endX,endY);
}
return find(matrix,target,beforeX,beforeY,harfX,harfY);
}
public boolean search(int[][] matrix, int target,int beforeX,int beforeY,int endX, int endY){
int row = matrix.length;
int column = matrix[0].length;
int positionX = beforeX;
int positionY = beforeY;
while(!((positionX == endX && positionY > endY) || positionX > endX)){
if(matrix[positionX][positionY] == target){
return true;
}
positionY ++;
if(positionY == column){
positionY = 0;
positionX++;
}
}
return false;
}
}
75. 颜色分类
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:
不能使用代码库中的排序函数来解决这道题。
示例:
输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]
进阶:
一个直观的解决方案是使用计数排序的两趟扫描算法。
首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。
你能想出一个仅使用常数空间的一趟扫描算法吗?
class Solution {
public void sortColors(int[] nums) {
int before = 0;
int end = nums.length - 1;
if(end <= 0){
return;
}
find(nums,before,end,1,nums[0]);
}
public void find(int[] nums,int before,int end,int positionBefore ,int val){
if(val == 0){
val = positionBefore<nums.length?nums[positionBefore]:-1;
nums[before] = 0;
before ++;
positionBefore++;
}else if(val == 2){
val = nums[end];
nums[end] = 2;
end --;
}else {
val = positionBefore<nums.length?nums[positionBefore]:-1;
positionBefore++;
}
if(positionBefore > end + 1){
for(int i = before;i <= end; i++){
nums[i] = 1;
}
return;
}
find(nums,before,end,positionBefore,val);
}
}