一些LeetCode(java语言)

1. 搜索旋转排序数组 II

链接:https://leetcode.com/problems/search-in-rotated-sorted-array-ii
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,0,1,2,2,5,6] 可能变为 [2,5,6,0,0,1,2] )。
编写一个函数来判断给定的目标值是否存在于数组中。若存在返回 true,否则返回 false。
示例 1:
输入: nums = [2,5,6,0,0,1,2], target = 0输出: true
示例 2:
输入: nums = [2,5,6,0,0,1,2], target = 3输出: false

分析:
注意看这个数组,一开始是升序排序的,然后旋转,这个时候我们把它看做两部分,两个部分都是升序排序的,为了方便描述,我就用 a b c d来代表这两个部分,它们的大小是这样的c < d < a < b(忽略等号),然后我们就可以依照这个大小顺序来与target进行比较了,具体的在代码里面有详细注释

 public boolean search(int[] nums, int target) {
    int i = nums.length;
    // 判断数组为空的情况
    if (i == 0){
      return false;
    }


    // 首先判断队首和队尾
    if (nums[0] == target || nums[i-1] == target){
      return true;
    }

    // 现在从队首开始
    if (target > nums[0]){
      for (int i1 = 1; i1 < nums.length; i1++) {
        // 如果比nums[0]小,说明已经到了第二队
        if (nums[0] > nums[i1]){
          return false;
        }
        if (target == nums[i1]){
          return true;
        }
      }
    }

    // 现在开始从队尾比较
    if (target < nums[i-1]){
      for (int i1 = nums.length - 2; i1 >= 0; i1--) {
        // 说明已经到了第一对
        if (nums[i-1] < nums[i1]){
          return false;
        }
        if (target == nums[i1]){
          return true;
        }
      }
    }
    return false;
  }

2. 汉诺塔问题

汉诺塔是一个数学谜题。有3根柱子(或木桩、塔)和一些可以在柱子之间来回移动的不同大小的圆盘。开始时,所有的圆盘按照从小到大的次序自上而下叠放在一根柱子上,形成一个圆锥结构。现在要求把整叠圆盘移动到另一根柱子上,移动时要遵守下面的规则:
每次只能移动一个圆盘。
每次移动,只能移动柱子最上面的一个圆盘到另一根柱子(这根柱子上有可能已有圆盘)。
任何时候不能出现大圆盘在小圆盘上方的情况。

分析:
使用递归的方法来解决,递归的两种情形:递归情形+基本情形(终止条件)

  1. 当只有一个盘子的时候,直接移动,可以作为递归的基本情形
  2. 当有两个盘子时,假如为1、2,柱子为A、B、C,那么移动情况就可以是1 --> B,2 --> C,1 --> C,可以作为递归的递归情形
    综上,我们把所有的盘子,只看做 nn-1,那么依据第二点的分析来看有以下代码
public class TowersOfHanoi {

  private static void fact(int n, char from, char to, char middle) {
    // 递归的基本情形 
    if (n == 1) {
      System.out.println("将disk1从柱子" + from + "移到柱子" + to);
    }else {
       // 注意看这三条语句,分别对应上面第二点分析的移动情况,n-1需要移动两次,而且它需要调用递归,而n只需要移动一次,所以直接打印
      fact(n - 1, from, middle, to);
      System.out.println("将disk" + n + "从柱子" + from + "移到柱子" + to);
      fact(n - 1, middle, to, from);
    }
  }

  public static void main(String[] args) {
    char a = 'a';
    char b = 'b';
    char c = 'c';
    fact(3, a, b, c);
  }
}

3. 非递归中序遍历二叉树

唉,这个是今天的一个痛啊,因为构造方法没有弄明白而导致浪费了很多时间,还好最后还是找出了问题是出在了哪里,不过还是没有搞清楚为什么那种方式会出错,以后再慢慢弄清楚吧
回到这个题,我觉得主要是两个地方吧:

  1. 二叉树的赋值问题

  2. 二叉树的非递归问题
    其实之前在学C语言的时候,给二叉树赋值我就觉得有点难,现在用java,本来想去找一下以前的笔记,想想两个语言还是有差别的,就只能硬着头皮写了,然后其实中序遍历二叉树使用递归方法还是很简单的,包括三种遍历方式,无外乎就是执行语句换一个顺序而已,但是非递归的话就要难一点了
    以上两个问题的解决:

  3. 使用一个二叉树类型的list,先将所有目标元素变为一个节点,存进去,然后利用一个循环,将list里面的元素加入二叉树里面去

  4. 使用一个二叉树类型的栈,保存右孩子,依照中序遍历的特点,遍历至最左下的节点,然后进行输出,具体的看代码

public class DemoTree {

  private int data;
  private DemoTree left;
  private DemoTree right;

  public DemoTree(int data) {
    this.data = data;
  }

  public DemoTree() {
  }

  public int getData() {
    return data;
  }

  public void setData(int data) {
    this.data = data;
  }

  public DemoTree getLeft() {
    return left;
  }

  public void setLeft(DemoTree left) {
    this.left = left;
  }

  public DemoTree getRight() {
    return right;
  }

  public void setRight(DemoTree right) {
    this.right = right;
  }
}

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class DemoTreeTest {

  private static DemoTree tree = new DemoTree();

  // 给二叉树赋值
  private static void create12(int[] obj){
    List<DemoTree> list = new ArrayList<>();
    for (int i : obj) {
      list.add(new DemoTree(i));
    }
    tree = list.get(0);
    for (int i = 0; i < obj.length / 2; i++) {
      list.get(i).setLeft(list.get(i * 2 + 1));
      if (i * 2 + 2 < obj.length) {
        list.get(i).setRight(list.get(i * 2 + 2));
      }
    }
  }

  // 非递归中序遍历
  private static void fact(DemoTree root) {
    // 使用栈来保存左孩子
    Stack<DemoTree> stack = new Stack<>();

    if (root == null){
      return;
    }

    while (true){
      while (root != null){
        stack.push(root);
        root = root.getLeft();
      }
      if (stack.isEmpty()){
        break;
      }else {
        root = stack.pop();
        System.out.print(root.getData() + " ");
        root = root.getRight();
      }
    }
  }

  public static void main(String[] args) {
    int[] objs = {1, 2, 3, 4, 5, 6, 7};
    create12(objs);
    fact(tree);
  }

}

4. 字符串的相关操作(stringbuilder、stringbuffer、stringTokenizer等)

1.反转字符串,一开始本来使用的是stringbuffer,但是后来发现想到stringbuilder效率要高一点,因为stringbuffer是线程安全的,安全虽好,但是降低了它的效率

  private static String reverse(String str) {
    int i, len = str.length();
    StringBuilder buffer = new StringBuilder(len);
    for (i = len - 1; i >= 0; i--) {
      buffer.append(str.charAt(i));
    }
    return buffer.toString();
  }

2.反转一个句子,这里只演示以空格进行分割的句子,分割的话就使用StringTokenizer来进行操作,然后对应分割之后的拼接,一开始是想到直接以string类型进行"+"拼接,但是这种方式会导致一些内存浪费等不好的一些,所以还是建议使用StringBuilder 来进行操作

 private static String reversSentence(String line){
    // 指定空格为分隔符
    StringTokenizer tokenizer = new StringTokenizer(line," ");
    StringBuilder str = new StringBuilder();
    while (tokenizer.hasMoreTokens()){
      // 因为要反转,所以直接在0位置进行插入即可
      // 先插入一个空格,相当于还原它本来的空格
      str.insert(0," " );
      str.insert(0, tokenizer.nextToken());
      }
     return str.toString();
     }

3.找出给定字符集的所有可能排列序列,这里主要用到递归,递归这个东西吧,有时候好理解,有时候又搞不懂,还是得多练,特别注意递归的条件和参数,比如说这里,for循环里面传的是list.size(),而这个大小是在每一次递归都会改变的,而正是因为这个改变,才能让prefix组合为一个可能的排序进而输出,然后最开始是直接给prefix赋空值的

 private static void palindrome(List<String> list, String prefix, int length) {
    if (prefix.length() == length) {
      System.out.println(prefix);
    }
    for (int i = 0; i < list.size(); i++) {
      List<String> tmp = new LinkedList<String>(list);
      palindrome(tmp, prefix + tmp.remove(i), length);
    }
  }
  public static void main(String[] args) {
    String[] array = new String[]{"a", "b", "c","d"};
    // 第一个参数是list类型,第二个参数直接传空字符串,第三个参数就是list的长度
    palindrome(Arrays.asList(array), "", array.length);
  }

5.找出只出现一次的数字

给定一个非空整数数组,除了某个元素只出现奇数次以外,其余每个元素均出现偶数次。找出那个只出现了奇数次的元素。要求具有线性时间复杂度,且不使用额外空间
分析:如果没有后面的要求的话,使用map来存储元素,是很简单的,但是要求不使用额外空间,就有点麻烦了,这里我介绍使用异或这种方法:a⊕b⊕a=(a⊕a)⊕b=0⊕b=b,然后偶数次的两两抵消,奇数次的最后只剩下一次

public class FindOnlyOne {
 private static int findOnlyOne(int[] nums){
   int ans = nums[0];
     for (int i = 1; i < nums.length; i++) {
       ans = ans ^ nums[i];
   }
   return ans;
 }

  public static void main(String[] args) {
    int[] nums = {1,2,3,3,2,1,1};
    System.out.println(findOnlyOne(nums));
  }
}

6.环形链表

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

 public boolean hasCycle(ListNode head) {
    Set<ListNode> nodesSeen = new HashSet<>();
    while (head != null) {
      if (nodesSeen.contains(head)) {
        return true;
      } else {
        nodesSeen.add(head);
      }
      head = head.next;
    }
    return false;
  }

7.单词拆分

给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
使用记忆化递归,一个HashMap保存之前检索过的串

class Solution{  
  HashMap<String,Boolean> map = new HashMap<>();
  public boolean wordBreak(String s, List<String> wordDict){

    return isContains(s,wordDict );
  }
  public boolean isContains(String s,List<String> wordDict){
    if ("".equals(s)){
      return true;
    }
    if(map.containsKey(s)){
      return map.get(s);
    }
    boolean result = false;
    for (int i = 0;i < s.length();i++){
      if (wordDict.contains(s.substring(0,i+1))){
        result = result || isContains(s.substring(i+1),wordDict );
        if(!result){
          map.put(s,false);
        }
      }
    }
    return result;
  }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Leetcode是一个在线的算法题库,Java是一种流行的编程语言Leetcode上的题目可以用Java语言来解决。Leetcode上有大量的题目,覆盖了各种难度级别和算法类型,包括数组、字符串、链表、树、图、动态规划、排序、贪心、回溯等等。Java作为一种高级编程语言,可以快速并且简洁地解决Leetcode上的问题。此外,Java还有丰富的类库和框架,方便开发人员使用。如果你想使用Java来解决Leetcode的问题,可以在Leetcode上完成编码,然后在测试通过后,下载题目页面中的PDF文件,进行备份和归档,以便在以后需要的时候查看。 总而言之,Leetcode Java PDF可以让您用Java语言解决Leetcode上的问题,并将完成的代码用PDF文件格式化,以备将来参考。 ### 回答2: LeetCode是一个在线的编程题库,提供了2000多道算法题目,并且还提供了讨论和答案解释。其中,JavaLeetCode支持的编程语言之一,因此学习Java语言可以更好地完成LeetCode算法的练习。此外,LeetCode还提供了PDF文档,以便有需要的用户离线学习或分享给其他人。这些PDF文档包括Java编程语言的基础知识和LeetCode的算法解析。如果想要成为一个出色的Java工程师或算法专家,深入学习LeetCode并掌握Java编程语言是非常重要的。因此,练习LeetCode算法和阅读编程语言的PDF文档对于提升编程技能和职业发展是非常有帮助的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值