【220221】838.推多米诺

题目:https://leetcode-cn.com/problems/push-dominoes/

BFS

逻辑:元素倒下后,状态不再改变。每个元素对应唯一的倒下时间。

//官方题解
class Solution {
    public String pushDominoes(String dominoes) {
        int n = dominoes.length();
        Deque<Integer> queue = new ArrayDeque<Integer>();
        int[] time = new int[n];
        Arrays.fill(time, -1);
        List<Character>[] force = new List[n];
        for (int i = 0; i < n; i++) {
            force[i] = new ArrayList<Character>();
        }
        
        //初始入队:正在倒下的元素
        for (int i = 0; i < n; i++) {
            char f = dominoes.charAt(i);
            if (f != '.') {
                queue.offer(i);
                time[i] = 0;
                force[i].add(f);
            }
        }
        
		//char数组便于字符串替换
        char[] res = new char[n];
        Arrays.fill(res, '.');
        while (!queue.isEmpty()) {
            int i = queue.poll();
            //【巧妙】只受到一个力才会倒
            //受力有且仅有两种,时间只会先后或同时
            //先后:后作用力不会施加于已有作用力的元素
            //同时:元素出队时,已到下一时间,力皆作用完毕
            if (force[i].size() == 1) {
                char f = force[i].get(0);
                res[i] = f;
                //根据力的方向确定下一个倒下的元素ni
                int ni = f == 'L' ? i - 1 : i + 1;
                //元素在数组范围内
                if (ni >= 0 && ni < n) {
                    int t = time[i];
                    if (time[ni] == -1) {
                    	//根据倒下时间筛选,未确定时间的入队
                        queue.offer(ni);
                        //入队后再确定时间
                        time[ni] = t + 1;
                        force[ni].add(f);
                    } else if (time[ni] == t + 1) {	//同时
                        force[ni].add(f);
                    }
                }
            }
        }
        return new String(res);
    }
}

双指针

转化:【区间问题】
区间:两端both为正在倒下的骨牌,它们包裹着若干个竖立的骨牌
状态:

  • 如果两边的骨牌同向,那么这段连续的竖立骨牌会倒向同一方向。
  • 如果两边的骨牌相对,那么这段骨牌会向中间倒。
  • 如果两边的骨牌相反,那么这段骨牌会保持竖立。

编程技巧:给dominoes最左边添加一个“L”,最右边添加一个“R”

//官方题解
class Solution {
    public String pushDominoes(String dominoes) {
        char[] s = dominoes.toCharArray();
        int n = s.length, i = 0;
        //【巧妙】不直接扩大dominoes,而是单独设区间端点left='L'
        char left = 'L';
        while (i < n) {
            int j = i;
            
			//找右端点:滤去中间竖立骨牌
            while (j < n && s[j] == '.') { // 找到一段连续的没有被推动的骨牌
                j++;
            }
            
            //【巧妙】不直接扩大dominoes,而是单独设区间端点right='R'
            char right = j < n ? s[j] : 'R';

			//判断区间两端方向
            if (left == right) { // 方向相同,那么这些竖立骨牌也会倒向同一方向
                while (i < j) {
                    s[i++] = right;
                }
            } else if (left == 'R' && right == 'L') { // 方向相对,那么就从两侧向中间倒
                int k = j - 1;
                while (i < k) {
                    s[i++] = 'R';
                    s[k--] = 'L';
                }
            }

			//迭代下个区间
            left = right;
            i = j + 1;
        }
        return new String(s);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值