java
1. 整数反转(限制长度)
class Solution {
public int reverse(int x) {
int temp;
if (x == 0) return 0;
if(x < 0) temp = -1;
else temp = 1;
x = Math.abs(x);
long result;
result = 0;
while(x > 0){
result = result * 10;
result += (x % 10);
x = x / 10;
}
result = result * temp;
// 反转后整数超过32位的有符号整数的范围,就返回0
return (int)result==result?(int)result:0;
}
}
2. 回文数
思路:反转数字,比较是否相同
class Solution {
public boolean isPalindrome(int x) {
if(x < 0) return false;
if(x < 10) return true;
int rev_num;
rev_num = 0;
int comperation;
comperation = x;
while(x > 0){
rev_num *= 10;
rev_num += x % 10;
x = x / 10;
}
if(rev_num == comperation) return true;
else return false;
}
}
3. 外观数列
思路:循环累加,循环调用
class Solution {
public String countAndSay(int n) {
String pre = "1";
String res = pre;
for(int i = 2; i <= n; i ++){
char preChar = pre.charAt(0);
StringBuilder temp = new StringBuilder();
int count = 1;
for(int j = 1; j < pre.length(); j ++){
char resChar = pre.charAt(j);
if(resChar == preChar){
count ++;
}
else{
temp.append(count);
temp.append(preChar);
count = 1;
}
preChar = resChar;
}
temp.append(count);
temp.append(preChar);
res = temp.toString();
pre = res;
}
return res;
}
}
4. 罗马数字转整数
思路: 替换特殊的字符,循环调用,不断累加
class Solution {
public int romanToInt(String s) {
s = s.replace("IV", "a");
s = s.replace("IX", "b");
s = s.replace("XL", "c");
s = s.replace("XC", "d");
s = s.replace("CD", "e");
s = s.replace("CM", "f");
int res = 0;
for(int i = 0; i < s.length(); i ++){
res +=f(s.charAt(i));
}
return res;
}
public int f(char c){
switch(c){
case 'I': return 1;
case 'V': return 5;
case 'X': return 10;
case 'L': return 50;
case 'C': return 100;
case 'D': return 500;
case 'M': return 1000;
case 'a': return 4;
case 'b': return 9;
case 'c': return 40;
case 'd': return 90;
case 'e': return 400;
case 'f': return 900;
}
return 0;
}
}
5. 最长公共前缀
思路: 最长公共前缀一定是最短的,长度小于等于strs所有元素中最短的字符串的长度。随便取一个字符串 s 作为公共前缀,若不符合要求,则缩短 s 的长度,直到符合要求或直到 s.length() 为 0
class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs.length == 0) return "";
String s = strs[0];
for(String string : strs){
while(!string.startsWith(s)){
if(s.length() == 0) return "";
s = s.substring(0, s.length() - 1);
}
}
return s;
}
}
6. 有效的括号
思路: 建立栈,遍历 s , 通过 c 与栈顶元素的比较, 判断不同括号是否按顺序配对。
class Solution {
public boolean isValid(String s) {
Stack<Character> temp = new Stack<Character>();
for(char c : s.toCharArray()){
if(c =='(') temp.push(')');
else if(c == '[') temp.push(']');
else if(c == '{') temp.push('}');
else if(temp.isEmpty() || c != temp.pop()){
return false;
}
}
return temp.isEmpty();
}
}
7. 给表达式添加运算符
思路: (*)
class Solution {
List<String> ans = new ArrayList<>();
String s;
int n, t;
public List<String> addOperators(String num, int target) {
s = num;
n = s.length();
t = target;
dfs(0, 0, 0, "");
return ans;
}
void dfs(int u, long prev, long cur, String ss){
if(u == n){
if(cur == t) ans.add(ss);
return;
}
for(int i = u; i < n; i ++){
if(i != u && s.charAt(u) == '0') break;
long next = Long.parseLong(s.substring(u, i + 1));
if(u == 0){
dfs(i + 1, next, next, "" + next);
}
else{
dfs(i + 1, next, cur + next, ss + "+" + next);
dfs(i + 1, -next, cur - next, ss + "-" + next);
long x = prev * next;
dfs(i + 1, x, cur - prev + x, ss + "*" + next);
}
}
}
}
8. 合并两个有序链表
思路: 创建新的链表, 遍历两个链表直到其中一个指空,将较小的值放入新建立的链表中。新链表注意保存表头位置,否则链表就丢了。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode head = new ListNode(0);
ListNode ans = head;
while(l1 != null && l2 != null){
if(l1.val < l2.val){
ans.next = l1;
ans = ans.next;
l1 = l1.next;
}
else{
ans.next = l2;
ans = ans.next;
l2 = l2.next;
}
}
if(l1 == null){
ans.next = l2;
}
else{
ans.next = l1;
}
return head.next;
}
}
9. 二叉搜索树中第k 小的元素
思路:遍历二叉树,将节点的值存入list中,排序后取第 k 个。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
List<Integer> list = new ArrayList();
public int kthSmallest(TreeNode root, int k) {
dfs(root);
Collections.sort(list);
return list.get(k - 1);
}
public void dfs(TreeNode root){
if(root == null) return;
list.add(root.val);
dfs(root.left);
dfs(root.right);
}
}
10. 删除有序数组中的重复项
思路:按照题意,必须修改原数组的元素,不能仅仅返回正确的长度,原数组本身也应该被修改为符合题目要求的形式。双重循环嵌套,若发现相同的元素就把后面的元素通过 for 循环整体向前移动,再比较移动后该位置的元素与开始的元素是否相同。若不相同,将对照元素移至第一个与之前的对照元素不相同的元素的位置。
class Solution {
public int removeDuplicates(int[] nums) {
int pre = 0;
int temp = nums.length;
for(int i = 1; i < temp; i ++){
if(nums[i] == nums[pre]){
for(int j = i + 1; j < temp; j ++){
nums[j - 1] = nums[j];
}
temp --;
i --;
}
else{
pre = i;
}
}
return temp;
}
}
11. 移除元素
思路: 思路与10(删除有序数组中的重复项)类似,遍历原数组,当数组元素等于给定值时,通过一个 for 循环将该元素后面的元素整体向前移动一位,并将数组长度减一。再对比移动后该位置的元素与给定值是否相同。
class Solution {
public int removeElement(int[] nums, int val) {
int temp = nums.length;
for(int i = 0; i < temp; i ++){
if(nums[i] == val){
for(int j = i + 1; j < temp; j ++){
nums[j - 1] = nums[j];
}
temp --;
i --;
}
}
return temp;
}
}
12. 实现strStr()
思路: 思路与5(最长公共前缀)类似,判断 needle 数组是否为 haystack 数组的前缀,若不是则从前面减掉一个 haystack 的元素, 并在循环判断过程中记录位置,增加 flag 变量判断循环是自己结束还是因为符合题目要求提前 break 出去。
class Solution {
public int strStr(String haystack, String needle) {
int count = 0;
int flag = 0;
while(haystack.length() >= needle.length()){
if(!haystack.startsWith(needle)){
haystack = haystack.substring(1, haystack.length());
count ++;
}
else{
flag = 1;
break;
}
}
if(flag == 1){
return count;
}
else{
return -1;
}
}
}
13. 搜索插入位置
思路: 遍历数组, 若找到与 target 相同的值则返回其下标, 若找到大于 target 的值则应将 target 值插入到该位置, 故返回第一个大于 target 的下标, 若最终没有找到大于或等于 target 的值, 则返回数组长度加一。
class Solution {
public int searchInsert(int[] nums, int target) {
for(int i = 0; i < nums.length; i ++){
if(nums[i] >= target) return i;
}
return nums.length;
}
}
14. 数字的补数
思路: (*)
class Solution {
public int findComplement(int num) {
int temp = num;
int c = 0;
while(temp > 0){
temp >>= 1;
c = (c << 1) + 1;
}
return num ^ c;
}
}
15. 最大子序和
思路: 遍历给定数组, 设置 pre 用来比较该下标元素大小与元素累计和的大小,设置 ans 比较之前的累计和比较大还是目前的累计和比较大,保留较大数。
class Solution {
public int maxSubArray(int[] nums) {
int pre = 0;
int ans = nums[0];
for(int i : nums){
pre = Math.max(pre + i, i);
ans = Math.max(pre, ans);
}
return ans;
}
}
16. 最后一个单词的长度
思路: 将给定字符串转为数组,从后往前遍历数组,在长度符合要求的范围内,在遍历过程中遇到的第一个元素不为空格而其前一个元素为空格,即为符合要求的元素位置,用 count 记录字符个数。
class Solution {
public int lengthOfLastWord(String s) {
int l = s.length();
char[] chars = s.toCharArray();
int count = 0;
for(int i = l - 1; i >= 0; i --){
if(chars[i] != ' '){
count ++;
if(i - 1 >= 0 && chars[i - 1] == ' '){
break;
}
}
}
return count;
}
}
17. 添加与搜索单词 - 数据结构设计
思路: 递归搜索,对 word 的字符是 ‘.’ 或不是 ‘.’ 分开讨论
class TrieNode{
boolean isWord;
TrieNode[] children = new TrieNode[26];
}
class WordDictionary {
private TrieNode root;
public WordDictionary() {
this.root = new TrieNode();
}
public void addWord(String word) {
var cur = root;
for(int i = 0; i < word.length(); i ++){
int ch = word.charAt(i) - 'a';
if(cur.children[ch] == null){
cur.children[ch] = new TrieNode();
}
cur = cur.children[ch];
}
cur.isWord = true;
}
public boolean search(String word) {
return search(word, 0, root);
}
public boolean search(String word, int begin, TrieNode root){
var cur = root;
for(int i = begin; i < word.length(); i ++){
if(word.charAt(i) == '.'){
for(var child : cur.children){
if(child != null && search(word, i + 1, child)){
return true;
}
}
return false;
}
int ch = word.charAt(i) - 'a';
if(cur.children[ch] == null){
return false;
}
cur = cur.children[ch];
}
return cur.isWord;
}
}
/**
* Your WordDictionary object will be instantiated and called as such:
* WordDictionary obj = new WordDictionary();
* obj.addWord(word);
* boolean param_2 = obj.search(word);
*/
18. 最小操作次数是数组元素相等
思路: 将每次操作会使 n - 1 个元素加 1 理解成 1 个元素减 1, 找出最小值将各个元素减去最小值得到的差值的和为题目要求返回值。
class Solution {
public int minMoves(int[] nums) {
int min = Integer.MAX_VALUE;
int res = 0;
for(int num : nums){
min = Math.min(min, num);
}
for(int a : nums){
res += a - min;
}
return res;
}
}
19. 加一
思路: 从后向前遍历数组, 考虑进位,若该下标元素不为 9 ,直接加 1 并返回该数组。 若为 9 则该下标元素变为 0 ,继续向后遍历直至找到一个不为 9 的元素, 或遍历结束退出循环。 退出循环相当于整个数组在加一后长度增加一位, 故定义一个新的数组, 使新数组的第一位元素为 1 , 其余元素与经过遍历处理后的原数组元素相同。
class Solution {
public int[] plusOne(int[] digits) {
for(int i = digits.length - 1; i >= 0; i --){
if(digits[i] != 9){
digits[i] ++;
return digits;
}
digits[i] = 0;
}
int[] res = new int[digits.length + 1];
res[0] = 1;
for(int i = 0; i < digits.length; i ++){
res[i + 1] = digits[i];
}
return res;
}
}
20. 检查句子中的数字是否递增
思路: 将字符串用 " " 分隔保存在数组中, 遍历数组, 该数组某一下标元素 >= ‘a’ 即该元素不为数字, 跳过该元素。 若该元素为数字, 对比该数字与上一个数字的大小。
class Solution {
public boolean areNumbersAscending(String s) {
String[] strs = s.split(" ");
int pre = -1;
for(int i = 0; i < strs.length; i ++){
if(strs[i].charAt(0) >= 'a'){
continue;
}
int cur = Integer.valueOf(strs[i]);
if(pre >= cur) return false;
pre = cur;
}
return true;
}
}
21. 二进制求和
思路: 将两个字符串补齐至同一长度, 从后往前循环进行加法运算, 记录进位,保存至 StringBuilder 类型的字符串中, 循环结束后若进位为 1 要多 append 一个进位, 将 StringBuilder 类型的字符串反转后转为 String 类型返回。
class Solution {
public String addBinary(String a, String b) {
if(b.length() > a.length()){
String t;
t = a;
a = b;
b = t;
}
while(a.length() - b.length() > 0){
b = "0" + b;
}
int pre = 0;
StringBuilder res = new StringBuilder();
for(int i = a.length() - 1; i >= 0; i --){
int num_1 = a.charAt(i) - '0';
int num_2 = b.charAt(i) - '0';
int temp = num_1 + num_2 + pre;
pre = temp / 2;
temp = temp % 2;
res.append(temp);
}
if(pre == 1){
res.append(pre);
}
return res.reverse().toString();
}
}
22. Sqrt(x)
思路: 直接遍历, 为防止溢出用 i > x / i 代替 i * i > x。
class Solution {
public int mySqrt(int x) {
int res = 0;
if(x <= 1) return x;
for(int i = 1; i <= x / 2; i ++){
if(i < x / i && (i + 1) > x / (i + 1)){
res = i;
break;
}
else if(i == x / i){
res = i;
break;
}
}
return res;
}
}class Solution {
public int mySqrt(int x) {
int res = 0;
if(x <= 1) return x;
for(int i = 1; i <= x / 2; i ++){
if(i < x / i && (i + 1) > x / (i + 1)){
res = i;
break;
}
else if(i == x / i){
res = i;
break;
}
}
return res;
}
}
23. 构造矩形
思路: 通过循环使用给定整数到对整数开方的向上取整,若给定整数对循环到的整数取余为 0 , 则判断 L 和 W 的差值,与前一个初步符合要求的差值进行比较, 选取较小的一个将数值存储到最终返回的数组中。
class Solution {
public int[] constructRectangle(int area) {
int[] res = new int[2];
int temp = Integer.MAX_VALUE;
for(int i = area; i >= Math.ceil(Math.sqrt(area)); i --){
if(area % i == 0){
if(temp <= i - (area / i)){
continue;
}
else{
temp = i - (area / i);
res[0] = i;
res[1] = area / i;
}
}
}
return res;
}
}
24. 爬楼梯
思路: 当楼梯阶数大于 2 时, 到达每个阶数都有两种可能。例如到达 n 阶 有 n - 1 和 n - 2 两种可能, 要得到到达第 n 阶的所有可能, 只要将到达 n - 1 和 到达 n - 2 的所有可能相加即可。
class Solution {
public int climbStairs(int n) {
if(n <= 2){
return n;
}
int a = 1;
int b =2;
for(int i = 3; i <= n; i ++){
int temp = a + b;
a = b;
b = temp;
}
return b;
}
}
25. 搜索二维矩阵 II
思路: 由矩阵的元素特性判断,从矩阵右上角的元素开始循环遍历矩阵,根据目标值和矩阵元素的关系移动搜索的下标,循环退出说明没有找到对应值。
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = 0;
int n = matrix[0].length - 1;
while(m < matrix.length && n >= 0){
if(matrix[m][n] == target){
return true;
}
else if(matrix[m][n] > target){
n --;
}
else{
m ++;
}
}
return false;
}
}
26. 下一个更大元素 I
思路: 由于 num1 是 nums2 的子集,故在 nums2 中一定可以找到 nums1 中的各个元素。在循环遍历 nums1 数组时,加一层循环寻找 nums2 中与 nums1 中该下标元素相同的元素,将其下标存入 count 中保存。再加一层循环,遍历 nums2 中 count 后的元素,寻找比 nums1 该下标元素大的元素,找到后退出循环。设置 flag ,判断循环是由于寻找到了符合要求的元素而退出还是循环条件不符合而退出。若没找到,记为 -1。
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int[] res = new int[nums1.length];
for(int i = 0; i < nums1.length; i ++){
int count = 0;
for(int j = 0; j < nums2.length; j ++){
if(nums2[j] == nums1[i]){
count = j;
break;
}
}
int flag = 0;
while(count < nums2.length){
if(nums2[count] > nums1[i]){
res[i] = nums2[count];
flag = 1;
break;
}
count ++;
}
if(flag == 0){
res[i] = -1;
}
}
return res;
}
}
27. 有效的完全平方数
思路: 完全平方数是前 n 个奇数的和,连续减去看是否能完全减完
class Solution {
public boolean isPerfectSquare(int num) {
int temp = 1;
while(num > 0){
num -= temp;
temp += 2;
}
return num == 0;
}
}
28. 删除排序链表中的重复元素
思路: 使用一个指针 p ,比较 p 和 p.next 的值,若相等则改变 p.next,若不等则将 p 向后移。注意循环条件。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode p = head;
while(p != null && p.next != null){
if(p.val == p.next.val){
p.next = p.next.next;
}
else{
p = p.next;
}
}
return head;
}
}
29. 合并两个有序数组
思路: 题目要求结果存储在 nums1 中,故把 nums2 中的元素放入 nums1 中再对 nums1 排序。
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int temp = 0;
while(n != 0){
nums1[m ++] = nums2[temp ++];
n --;
}
Arrays.sort(nums1);
}
}