为了提高自己的编程能力,我决定在工作之余将leetcode的算法题刷一遍,现在开始记录刷题过程和心得。
首先是一些简单的算法题和自己的解答,先记录20道。
给定一个整数数组 nums
和一个目标值 target
,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] array = new int[2];
int length = nums.length;
for(int i = 0;i<length-1;++i)
for(int j = i+1;j<length;j++){
if(nums[i]+nums[j]==target){
array[0]=i;
array[1]=j;
break;
}
}
return array;
}
}
思路:暴力破解,类冒泡法来找出满足条件的两个整数,时间复杂度为O(n²)
2.整数反转
class Solution {
public int reverse(int x) {
try{
String num = String.valueOf(x);
char[] c1 = num.toCharArray();
char[] c2 = new char[c1.length];
int i = c1.length;
for (Character c :c1){
c2[--i] = c ;
}
num = new String(c2);
int result;
if(c2[c2.length-1]=='-') {
num = num.substring(0, c2.length-1);
result = -Integer.parseInt(num);
}else {
result = Integer.parseInt(num);
}
return result;
}catch(Exception e){
return 0;
}
}
}
思路:暴力破解,先将数字转为String类,然后重新构建一个数组存储数字,时间复杂度为O(n),空间复杂度为O(n)
3.回文数
class Solution {
public boolean isPalindrome(int x) {
if(x < 0)
return false;
int cur = 0;
int num = x;
while(num != 0) {
cur = cur * 10 + num % 10;
num /= 10;
}
return cur == x;
}
}
思路:利用旧数构建一个新数,如果是回文数,两个数字相等。时间复杂度为O(n)
4.罗马数字转整数
罗马数字包含以下七种字符: 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 的范围内。
class Solution {
public int romanToInt(String s) {
int result = 0;
char[] chars = s.toCharArray();
int i = 0;
int length = chars.length;
while (i < length){
switch (chars[i]) {
case 'C': result += 100;
if (i + 1 < length && (chars[i + 1] == 'D' || chars[i + 1] == 'M')) {
result -= 200;
}
break;
case 'D': result += 500;
break;
case 'M': result += 1000;
break;
case 'X': result += 10;
if (i + 1 < length && (chars[i + 1] == 'L' || chars[i + 1] == 'C')) {
result -= 20;
}
break;
case 'L': result += 50;
break;
case 'I':result+=1;
if (i + 1 < length && (chars[i + 1] == 'V' || chars[i + 1] == 'X')) {
result -= 2;
}
break;
case 'V':result+=5;
break;
}
i++;
}
return result;
}
}
思路:遇到相同的字符应该采取相同的操作,但是考虑到4和9的区别,要判断部分字符下一个字符是什么,用switch选择,时间复杂度为O(n)
5.最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""
。
class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs==null||strs.length==0){
return "";
}
int length = strs[0].length();
int k = 0;
for(int i = 1;i<strs.length;++i){//获得字符串中最短的长度
if(strs[i].length()<length){
length = strs[i].length();
k = i;//记录最短长度那个字符串位置
}
}
String s = strs[k];
while(length>0){//字符串长度
int temp = 0;//记录有几个一样的
for(String str :strs){
if(!str.startsWith(s)){//如果字符串不是以它为开头
length--;//字符串长度-1;
s = s.substring(0,length);//字符串-1
break;
}else {
temp++;
}
}
if(temp==strs.length)
return s;
}
return "";//length==0,返回""
}
}
6.有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
class Solution {
public boolean isValid(String s) {
if(s.equals("")){
return true;
}
char[] str = s.toCharArray();
Stack<Character> stack = new Stack<>();
int i = 0;
for(Character c :str){
if(stack.size()==0){
if(str[i]=='}'||str[i]==')'||str[i]==']'){
return false;
}
}
if(c.equals('[')||c.equals('{')||c.equals('(')){//放入栈中
stack.push(c);
}else {
Character c2 = stack.pop();
switch (c){
case ']':if(!c2.equals('['))
return false;
break;
case '}':if(!c2.equals('{'))
return false;
break;
case ')':if(!c2.equals('('))
return false;
break;
}
}
i++;
}
return stack.size() <= 0;
}
}
7.合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入: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 = new ListNode(-1);
ListNode h = head;
while (l1!=null&&l2!=null){
if(l1.val<l2.val){
h.next = l1;
l1 = l1.next;
}else {
h.next = l2;
l2 = l2.next;
}
h = h.next;
}
if (l1!=null){
h.next = l1;
}
if (l2!=null){
h.next = l2;
}
return head.next;
}
}
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
class Solution {
public int removeDuplicates(int[] nums) {
if (nums.length == 0) return 0;
int i = 0;
for (int j = 1; j < nums.length; j++) {
if (nums[j] != nums[i]) {
i++;
nums[i] = nums[j];
}
}
return i + 1;
}
}
9.移除元素
给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
class Solution {
public int removeElement(int[] nums, int val) {
int target=0;//目标数组指针
for(int i = 0;i<nums.length;++i)
if(nums[i]!=val)
nums[target++]=nums[i];
return target;
}
}
10.实现strStr()
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
class Solution {
public int strStr(String haystack, String needle) {
if(needle.equals(""))
return 0;
char[] h = haystack.toCharArray();//长
char[] n = needle.toCharArray();//短
int k=0;//k作为记录长字符串的指针
while(k<=h.length-n.length){//k自增次数
int t = 0;
for(int i = 0;i<n.length;++i){//i作为长字符串的指针
if(h[k+i]!=n[i]){
k++;
break;
}else {
t++;
}
}
if(t==n.length){
return k;
}
}
return -1;
}
}
11.搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
class Solution {
public int searchInsert(int[] nums, int target) {
int i = 0;
for(;i<nums.length;++i){
if(target<=nums[i]){
return i;
}
}
return i;
}
}
12.报数
报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:
1. 1
2. 11
3. 21
4. 1211
5. 111221
1 被读作 "one 1" ("一个一") , 即 11。
11 被读作 "two 1s" ("两个一"), 即 21。
21 被读作 "one 2", "one 1" ("一个二" , "一个一") , 即 1211。
给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。
注意:整数顺序将表示为一个字符串。
class Solution {
public String countAndSay(int n) {
if(n==1){
return "1";
}else if(n==2){
return "11";
}
int i = 3;
String s = "21";
Map<Integer,Character> map = new HashMap<>();
while (i < n){
StringBuilder stringBuilder = new StringBuilder();
char[] chars = s.toCharArray();
char temp = chars[0];
int count = 0;
int j = 0;
while (j<chars.length){
if (chars[j] == temp) {
count++;
++j;
continue;
}
stringBuilder.append(count).append(temp);
temp = chars[j];
count = 0;
}
stringBuilder.append(count).append(temp);
i++;
s = stringBuilder.toString();
System.out.println("字符串是:"+s);
}
return s;
}
}
13.最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
class Solution {
public int maxSubArray(int[] nums) {
int max = nums[0];
for(int i=0;i<nums.length;++i) {
int sum = nums[i] + Solution.getRightMaxAnaLeftSum(nums, i);
if (sum > max) {
max = sum;
}
}
return max;
}
private static int getRightMaxAnaLeftSum(int[] nums,int k){
int rigntMax = 0;//右边相加最大值
int rightSum = 0;//右边总和
for(int i=k+1;i<nums.length;++i){
rightSum += nums[i];//右边总和
if(rightSum>0){
if(rightSum>rigntMax){
rigntMax = rightSum;
}
}
}
int leftMax = 0;
int leftSum = 0;
for(int i=k-1;i>=0;--i){
leftSum +=nums[i];
if(leftSum>0){
if(leftSum>leftMax){
leftMax = leftSum;
}
}
}
return rigntMax+leftMax;
}
}
ps:该题可以用动态规划实现,会更简单且性能更好
14.最后一个单词的长度
给定一个仅包含大小写字母和空格 ' ' 的字符串,返回其最后一个单词的长度。
如果不存在最后一个单词,请返回 0 。
说明:一个单词是指由字母组成,但不包含任何空格的字符串。
class Solution {
public int lengthOfLastWord(String s) {
if(s.equals(""))
return 0;
char[] str = s.toCharArray();
int sum = 0;
boolean Switch =false;
for(int i = str.length -1 ;i>=0;--i){
if(str[i]!=' '){
Switch =true;
sum++;
}
else if(Switch&&str[i]==' '){
break;
}
}
return sum;
}
}
15.加一
给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
class Solution {
public int[] plusOne(int[] digits) {
int nine = 0;
for(int i :digits){
if(i==9){
nine++;
}
}
if(nine==digits.length){//全是9的情况
int[] nums = new int[digits.length+1];
nums[0] = 1;
for(int i=1;i<nums.length;++i){
nums[i]=0;
}
return nums;
}
if(digits[digits.length-1]!=9){//最后一个数不是9的情况
digits[digits.length-1]++;
return digits;
}
//最后一个是9的情况
digits[digits.length-1]=0;
for(int i=digits.length-2;i>=0;--i){
if(digits[i]!=9){
digits[i]++;
break;
}else {
digits[i]=0;
}
}
return digits;
}
}
16.二进制求和
给定两个二进制字符串,返回他们的和(用二进制表示)。
输入为非空字符串且只包含数字 1
和 0
。
class Solution {
public String addBinary(String a, String b) {
char[] binary_a = a.toCharArray();//a数组
char[] binary_b = b.toCharArray();//b数组
char[] short_array,long_array;
if(binary_a.length<binary_b.length){
short_array = binary_a;
long_array = binary_b;
}else {
short_array = binary_b;
long_array = binary_a;
}
//重新构造短的数组
char[] new_short = new char[long_array.length];
for(int j = long_array.length-1,t = short_array.length-1 ;j>=0;j--,t--){
if(t<0){
new_short[j]='0';
}else {
new_short[j] = short_array[t];
}
}
System.out.println("新构造的数组:");
for (char c : new_short) {
System.out.print(c + ",");
}
int jinwei = 0;//进位信息
int i = long_array.length- 1;//循环条件
System.out.println(" ");
List<Integer> list = new ArrayList<>();//存入结果
int a_value,b_value;
while(i>=0){
a_value = new_short[i]=='0'?0:1;
b_value = long_array[i]=='0'?0:1;
System.out.println("进位:"+jinwei+",a_value:"+a_value+",b_value:"+b_value);
int value = a_value+b_value+jinwei;
list.add(value);
System.out.println("相加和为:"+value);
if(value==2||value==3){
jinwei = 1;
}else{
jinwei = 0;
}
i--;
}
if(jinwei==1){
list.add(1);
}
char[] result = new char[list.size()];
char temp;
for(int j =list.size()-1,t=0;j>=0;--j,t++){
temp = list.get(t)%2==1?'1':'0';
result[j] = temp;
}
return new String(result);
}
}
17.爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
class Solution {
public int climbStairs(int n) {
if (n == 1) {
return 1;
}
int first = 1;
int second = 2;
for (int i = 3; i <= n; i++) {
int third = first + second;
first = second;
second = third;
}
return second;
}
}
18.删除排序链表中的重复元素
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode dummy = head;
if(head==null)
return null;
int value=head.val;//头结点的值
while (head.next!=null){
if(value!=head.next.val){
value = head.next.val;//改值
head = head.next;
}else {
head.next = head.next.next;
}
}
return dummy;
}
}
19.合并两个有序数组
给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int p = m-- + n-- - 1;
while (m >= 0 && n >= 0) {
nums1[p--] = nums1[m] > nums2[n] ? nums1[m--] : nums2[n--];
}
while (n >= 0) {
nums1[p--] = nums2[n--];
}
}
}
20.只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
class Solution {
public int singleNumber(int[] nums) {
int result = 0;
for(int i : nums){
result ^=i;
}
return result;
}
}
总结:动态规划部分不太熟练,没有养成良好的编程思维,习惯采用暴力破解,需要多加练习来养成良好的编程思维!