LeetCode算法题完成计划(一)

本文记录了作者在刷LeetCode算法题的过程中,对20道题目(如两数之和、整数反转、回文数等)的解题思路和心得,强调了动态规划的重要性,并指出自身在编程思维上的不足,希望通过不断练习提升编程能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为了提高自己的编程能力,我决定在工作之余将leetcode的算法题刷一遍,现在开始记录刷题过程和心得。

首先是一些简单的算法题和自己的解答,先记录20道。

1. 两数之和

给定一个整数数组 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;
    }
}

8.删除排序数组中的重复项

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 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;
    }
}

 

总结:动态规划部分不太熟练,没有养成良好的编程思维,习惯采用暴力破解,需要多加练习来养成良好的编程思维!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值